Code

Ticket #7789: 7789_fields_3.diff

File 7789_fields_3.diff, 3.6 KB (added by arne, 6 years ago)

Similar to 7789_fields_2.diff, but this time returning unicode strings from the binary fields.

Line 
1Index: db/models/fields/__init__.py
2===================================================================
3--- db/models/fields/__init__.py        (revision 8255)
4+++ db/models/fields/__init__.py        (working copy)
5@@ -150,8 +150,13 @@
6         # mapped to one of the built-in Django field types. In this case, you
7         # can implement db_type() instead of get_internal_type() to specify
8         # exactly which wacky database column type you want to use.
9-        data = DictWrapper(self.__dict__, connection.ops.quote_name, "qn_")
10         try:
11+            data = get_creation_module().backend_parameters(self, self.__dict__)
12+        except AttributeError:
13+            # No backend_parameters provided in backend
14+            data = self.__dict__
15+        data = DictWrapper(data, connection.ops.quote_name, "qn_")
16+        try:
17             return get_creation_module().DATA_TYPES[self.get_internal_type()] % data
18         except KeyError:
19             return None
20Index: db/backends/mysql/base.py
21===================================================================
22--- db/backends/mysql/base.py   (revision 8255)
23+++ db/backends/mysql/base.py   (working copy)
24@@ -21,7 +21,7 @@
25     raise ImproperlyConfigured("MySQLdb-1.2.1p2 or newer is required; you have %s" % Database.__version__)
26 
27 from MySQLdb.converters import conversions
28-from MySQLdb.constants import FIELD_TYPE
29+from MySQLdb.constants import FIELD_TYPE, FLAG
30 import re
31 
32 # Raise exceptions for database warnings if DEBUG is on
33@@ -39,11 +39,18 @@
34 # TIME columns as timedelta -- they are more like timedelta in terms of actual
35 # behavior as they are signed and include days -- and Django expects time, so
36 # we still need to override that.
37+
38 django_conversions = conversions.copy()
39 django_conversions.update({
40     FIELD_TYPE.TIME: util.typecast_time,
41     FIELD_TYPE.DECIMAL: util.typecast_decimal,
42     FIELD_TYPE.NEWDECIMAL: util.typecast_decimal,
43+    # By default, mysqldb will return VARCHAR BINARY fields as type str.
44+    # This is a bad idea, as BINARY doesn't indicate that it's arbitrary
45+    # binary data, but that collation uses the binary representation.
46+    # Replacing the list makes it return unicode; mysqldb later adds
47+    # another list entry for non-binary fields.
48+    FIELD_TYPE.VARCHAR: [(FLAG.BINARY, lambda s: s.decode('utf-8'))],
49 })
50 
51 # This should match the numerical portion of the version numbers (we can treat
52Index: db/backends/mysql/creation.py
53===================================================================
54--- db/backends/mysql/creation.py       (revision 8255)
55+++ db/backends/mysql/creation.py       (working copy)
56@@ -5,7 +5,7 @@
57 DATA_TYPES = {
58     'AutoField':         'integer AUTO_INCREMENT',
59     'BooleanField':      'bool',
60-    'CharField':         'varchar(%(max_length)s)',
61+    'CharField':         'varchar(%(max_length)s) %(binary)s',
62     'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
63     'DateField':         'date',
64     'DateTimeField':     'datetime',
65@@ -20,9 +20,19 @@
66     'PhoneNumberField':  'varchar(20)',
67     'PositiveIntegerField': 'integer UNSIGNED',
68     'PositiveSmallIntegerField': 'smallint UNSIGNED',
69-    'SlugField':         'varchar(%(max_length)s)',
70+    'SlugField':         'varchar(%(max_length)s) BINARY',
71     'SmallIntegerField': 'smallint',
72     'TextField':         'longtext',
73     'TimeField':         'time',
74     'USStateField':      'varchar(2)',
75 }
76+
77+
78+def backend_parameters(field, field_dict):
79+    """
80+    For MySQL a unique CharField has to be created as a BINARY column as
81+    database level.
82+    """
83+    if field.unique and field.get_internal_type() == 'CharField':
84+        return dict(field_dict, binary='BINARY')
85+    return dict(field_dict, binary='')