🌐 AI搜索 & 代理 主页
Skip to content

Commit bd24fee

Browse files
committed
BUG#37047789: Python connector does not support Django enum
This patch fixes the issue where pure-python mode of Connector/Python does not work properly while executing queries via Django ORM when Django Enum objects or ChoiceField is being used in a django model. Change-Id: I6f8fcfde23b34c94cdc7f4486c2c614d843389cd
1 parent cffa5ab commit bd24fee

File tree

4 files changed

+63
-2
lines changed

4 files changed

+63
-2
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ v9.4.0
1313

1414
- BUG#37820231: Text based django ORM filters doesn't work with Connector/Python
1515
- BUG#37806057: Rename extra option (when installing wheel package) to install webauthn functionality dependencies
16+
- BUG#37047789: Python connector does not support Django enum
1617
- BUG#36452514: Missing version info resources
1718
- BUG#34950958: MySQL Python Connector doesn't work with ssh in the same process
1819
- BUG#34844347: Freezes on connection via sshtunnel

mysql-connector-python/lib/mysql/connector/conversion.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import time
3636

3737
from decimal import Decimal
38+
from enum import Enum
3839
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
3940

4041
from .constants import (
@@ -233,6 +234,8 @@ def quote(buf: Optional[Union[float, int, Decimal, HexLiteral, bytes]]) -> bytes
233234

234235
def to_mysql(self, value: MySQLConvertibleType) -> MySQLProducedType:
235236
"""Convert Python data type to MySQL"""
237+
if isinstance(value, Enum):
238+
value = value.value
236239
type_name = value.__class__.__name__.lower()
237240
try:
238241
converted: MySQLProducedType = getattr(self, f"_{type_name}_to_mysql")(

mysql-connector-python/lib/mysql/connector/types.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
from datetime import date, datetime, time, timedelta
3535
from decimal import Decimal
36+
from enum import Enum
3637
from time import struct_time
3738
from typing import (
3839
TYPE_CHECKING,
@@ -105,7 +106,7 @@ class MySQLScriptPartition(TypedDict):
105106
"""
106107

107108
# pylint: disable=invalid-name
108-
MySQLConvertibleType = Union[BinaryProtocolType, bool, struct_time]
109+
MySQLConvertibleType = Union[BinaryProtocolType, Enum, bool, struct_time]
109110
"""
110111
MySQL convertible Python types - Python types consumed by the built-in converter that
111112
can be converted to MySQL. It's a superset of `BinaryProtocolType`.

mysql-connector-python/tests/test_django.py

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,15 @@
105105
import django.db # pylint: disable=W0611
106106

107107
from django.core.exceptions import ImproperlyConfigured
108-
from django.db import connection
108+
from django.db import connection, models
109109
from django.db.backends.signals import connection_created
110110
from django.db.utils import DEFAULT_DB_ALIAS, load_backend
111111
from django.utils.safestring import SafeText
112112

113113
import mysql.connector
114114

115115
from mysql.connector.conversion import MySQLConverter
116+
from mysql.connector.django.base import CursorWrapper
116117
from mysql.connector.django.introspection import FieldInfo
117118
from mysql.connector.errors import ProgrammingError
118119

@@ -627,3 +628,58 @@ def test_missing_config(self):
627628
cnx_params = cnx.get_connection_params()
628629
self.assertTrue(cnx_params["raise_on_warnings"])
629630
del settings.DATABASES["default"]["OPTIONS"]
631+
632+
633+
class BugOra37047789(tests.MySQLConnectorTests):
634+
"""BUG#37047789: Python connector does not support Django enum
635+
636+
Django Enumeration types are not getting converted into MySQLConvertibleType
637+
thus, query execution via Django ORM using Connector/Python is failing when
638+
a model field with enum choices are being used.
639+
640+
This patch fixes the issue by changing the Enum object being passed to the
641+
conversation module to its underlying value before conversion to MySQL type
642+
takes place using the built-in property `value`, which already exists in every
643+
Enum objects.
644+
"""
645+
646+
table_name = "BugOra37047789"
647+
648+
class Priority(models.IntegerChoices):
649+
LOW = 1, 'Low'
650+
MEDIUM = 2, 'Medium'
651+
HIGH = 3, 'High'
652+
653+
class Status(models.TextChoices):
654+
DRAFT = 'draft', 'Draft'
655+
PUBLISHED = 'published', 'Published'
656+
657+
dbconfig = tests.get_mysql_config()
658+
659+
def setUp(self):
660+
with mysql.connector.connect(**self.dbconfig) as cnx:
661+
cnx.cmd_query(f"""
662+
CREATE TABLE {self.table_name} (
663+
priority INT NOT NULL DEFAULT 1,
664+
status varchar(10) NOT NULL DEFAULT 'draft'
665+
)
666+
""")
667+
cnx.commit()
668+
669+
def tearDown(self):
670+
with mysql.connector.connect(**self.dbconfig) as cnx:
671+
cnx.cmd_query(f"DROP TABLE {self.table_name}")
672+
673+
@tests.foreach_cnx()
674+
def test_django_enum_support(self):
675+
cnx_cur = self.cnx.cursor()
676+
django_cur = CursorWrapper(cnx_cur)
677+
django_cur.execute(
678+
f"INSERT INTO {self.table_name} VALUES (%s, %s)",
679+
(self.Priority.HIGH, self.Status.PUBLISHED)
680+
)
681+
django_cur.execute(
682+
f"INSERT INTO {self.table_name} VALUES (%(priority)s, %(status)s)",
683+
{'priority': self.Priority.HIGH, 'status': self.Status.PUBLISHED}
684+
)
685+
cnx_cur.close()

0 commit comments

Comments
 (0)