Code

Ticket #2417: patch.2.txt

File patch.2.txt, 9.2 KB (added by alex_koval, 5 years ago)

patch against latest trunk (tested to work on 8960...9002)

Line 
1Index: django/db/models/fields/__init__.py
2===================================================================
3--- django/db/models/fields/__init__.py (revision 9285)
4+++ django/db/models/fields/__init__.py (working copy)
5@@ -417,6 +417,26 @@
6         defaults.update(kwargs)
7         return super(CharField, self).formfield(**defaults)
8 
9+
10+class BinaryField(Field):
11+    """Sometimes we have fields that need to store a small amount of binary
12+    data. This is different then a varchar on postgresql at least because it
13+    will not allow fields that are just nul bytes.
14+    """
15+
16+    def get_internal_type(self):
17+        return "BinaryField"
18+
19+class BlobField(Field):
20+    """Sometimes we have fields that need to store a large amounts of binary
21+    data.
22+    """
23+
24+    def get_internal_type(self):
25+        return "BlobField"
26+
27+
28+
29 # TODO: Maybe move this into contrib, because it's specialized.
30 class CommaSeparatedIntegerField(CharField):
31     def formfield(self, **kwargs):
32Index: django/db/backends/postgresql/introspection.py
33===================================================================
34--- django/db/backends/postgresql/introspection.py      (revision 9285)
35+++ django/db/backends/postgresql/introspection.py      (working copy)
36@@ -4,6 +4,7 @@
37     # Maps type codes to Django Field types.
38     data_types_reverse = {
39         16: 'BooleanField',
40+        17: 'BlobField',
41         21: 'SmallIntegerField',
42         23: 'IntegerField',
43         25: 'TextField',
44Index: django/db/backends/postgresql/creation.py
45===================================================================
46--- django/db/backends/postgresql/creation.py   (revision 9285)
47+++ django/db/backends/postgresql/creation.py   (working copy)
48@@ -8,6 +8,8 @@
49     # If a column type is set to None, it won't be included in the output.
50     data_types = {
51         'AutoField':         'serial',
52+        'BinaryField':       'bytea',
53+        'BlobField':         'bytea',
54         'BooleanField':      'boolean',
55         'CharField':         'varchar(%(max_length)s)',
56         'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
57Index: django/db/backends/sqlite3/creation.py
58===================================================================
59--- django/db/backends/sqlite3/creation.py      (revision 9285)
60+++ django/db/backends/sqlite3/creation.py      (working copy)
61@@ -9,6 +9,8 @@
62     # schema inspection is more useful.
63     data_types = {
64         'AutoField':                    'integer',
65+        'BinaryField':                  'BLOB',
66+        'BlobField':                    'BLOB',
67         'BooleanField':                 'bool',
68         'CharField':                    'varchar(%(max_length)s)',
69         'CommaSeparatedIntegerField':   'varchar(%(max_length)s)',
70Index: django/db/backends/mysql/base.py
71===================================================================
72--- django/db/backends/mysql/base.py    (revision 9285)
73+++ django/db/backends/mysql/base.py    (working copy)
74@@ -29,6 +29,7 @@
75 from django.db.backends.mysql.creation import DatabaseCreation
76 from django.db.backends.mysql.introspection import DatabaseIntrospection
77 from django.db.backends.mysql.validation import DatabaseValidation
78+from django.utils.encoding import smart_unicode
79 
80 # Raise exceptions for database warnings if DEBUG is on
81 from django.conf import settings
82@@ -46,10 +47,22 @@
83 # behavior as they are signed and include days -- and Django expects time, so
84 # we still need to override that.
85 django_conversions = conversions.copy()
86+
87+binstr_conversion = [(FLAG.BINARY, buffer),
88+                     (FLAG.BLOB, smart_unicode),
89+                     ]
90+
91 django_conversions.update({
92     FIELD_TYPE.TIME: util.typecast_time,
93     FIELD_TYPE.DECIMAL: util.typecast_decimal,
94     FIELD_TYPE.NEWDECIMAL: util.typecast_decimal,
95+    FIELD_TYPE.TINY_BLOB: binstr_conversion,
96+    FIELD_TYPE.MEDIUM_BLOB: binstr_conversion,
97+    FIELD_TYPE.LONG_BLOB: binstr_conversion,
98+    FIELD_TYPE.BLOB: binstr_conversion,
99+    FIELD_TYPE.VARCHAR: binstr_conversion,
100+    FIELD_TYPE.VAR_STRING: binstr_conversion,
101+    FIELD_TYPE.STRING: binstr_conversion,
102 })
103 
104 # This should match the numerical portion of the version numbers (we can treat
105Index: django/db/backends/mysql/introspection.py
106===================================================================
107--- django/db/backends/mysql/introspection.py   (revision 9285)
108+++ django/db/backends/mysql/introspection.py   (working copy)
109@@ -7,7 +7,10 @@
110 
111 class DatabaseIntrospection(BaseDatabaseIntrospection):
112     data_types_reverse = {
113-        FIELD_TYPE.BLOB: 'TextField',
114+        FIELD_TYPE.BLOB: 'BlobField',
115+        FIELD_TYPE.LONG_BLOB: 'BlobField',
116+        FIELD_TYPE.TINY_BLOB: 'BlobField',
117+        FIELD_TYPE.MEDIUM_BLOB: 'BlobField',
118         FIELD_TYPE.CHAR: 'CharField',
119         FIELD_TYPE.DECIMAL: 'DecimalField',
120         FIELD_TYPE.NEWDECIMAL: 'DecimalField',
121Index: django/db/backends/mysql/creation.py
122===================================================================
123--- django/db/backends/mysql/creation.py        (revision 9285)
124+++ django/db/backends/mysql/creation.py        (working copy)
125@@ -8,6 +8,8 @@
126     # If a column type is set to None, it won't be included in the output.
127     data_types = {
128         'AutoField':         'integer AUTO_INCREMENT',
129+        'BinaryField':       'varbinary(%(max_length)s)',
130+        'BlobField':         'blob',
131         'BooleanField':      'bool',
132         'CharField':         'varchar(%(max_length)s)',
133         'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
134@@ -63,4 +65,4 @@
135                 field.rel.to._meta.db_table, field.rel.to._meta.pk.column)
136             ]
137         return table_output, deferred
138-       
139\ No newline at end of file
140+       
141Index: django/db/backends/__init__.py
142===================================================================
143--- django/db/backends/__init__.py      (revision 9285)
144+++ django/db/backends/__init__.py      (working copy)
145@@ -164,7 +164,11 @@
146         from django.utils.encoding import smart_unicode, force_unicode
147 
148         # Convert params to contain Unicode values.
149-        to_unicode = lambda s: force_unicode(s, strings_only=True)
150+        def to_unicode(s):
151+            if isinstance(s,buffer):
152+                return u'<binary data buffer size %d>' % len(s)
153+            return force_unicode(s, strings_only=True)
154+       
155         if isinstance(params, (list, tuple)):
156             u_params = tuple([to_unicode(val) for val in params])
157         else:
158Index: tests/modeltests/binary/__init__.py
159===================================================================
160Index: tests/modeltests/binary/tests.py
161===================================================================
162--- tests/modeltests/binary/tests.py    (revision 0)
163+++ tests/modeltests/binary/tests.py    (revision 0)
164@@ -0,0 +1,70 @@
165+#!/usr/bin/python
166+# encoding: utf-8
167+
168+try:
169+     from models import Document, BinaryFieldTest
170+except: # for local testing
171+     from binary.models import Document, BinaryFieldTest
172+     
173+import unittest
174+
175+
176+class BlobFieldTests( unittest.TestCase ):
177+   
178+     def test_blob(self):
179+         test_title = u'Hi there! привет!'
180+         test_descr = u'описание документа'
181+
182+         s = ''
183+         for i in range(0,256):
184+              s += chr(i)
185+         s+= '\xff\xff'
186+             
187+         
188+         test_data = buffer(s)
189+         
190+         doc = Document(title = test_title,
191+                        description = test_descr,
192+                        document = test_data)
193+         doc.save()
194+         doc_id = doc.id
195+         doc = None
196+         doc = Document.objects.get(id=doc_id)
197+         assert doc.title == test_title, type(doc.title)
198+         assert doc.description == test_descr, type(doc.description)
199+         assert doc.document == test_data, type(doc.document)
200+
201+class BinaryFieldTests( unittest.TestCase ):
202+   
203+     def test_binary(self):
204+         test_title = u'Hi there! привет!'
205+
206+         s = ''
207+         for i in range(0,10):
208+              s += chr(i)
209+
210+         s+= '\xff\xff'
211+             
212+         test_data = buffer(s)
213+         
214+
215+         tst = BinaryFieldTest(title = test_title,
216+                          binfield = test_data)
217+         tst.save()
218+         tst_id = tst.id
219+         tst = None
220+         tst = BinaryFieldTest.objects.get(id=tst_id)
221+         assert tst.title == test_title, type(tst.title)
222+         assert tst.binfield == test_data, type(tst.binfield)
223+                         
224+
225+def test_suite():
226+    return unittest.TestSuite((
227+        unittest.makeSuite(BlobFieldTests),
228+        unittest.makeSuite(BinaryFieldTests)
229+        ))
230+
231+
232+
233+if __name__ == '__main__':
234+    unittest.main(defaultTest='test_suite')
235Index: tests/modeltests/binary/models.py
236===================================================================
237--- tests/modeltests/binary/models.py   (revision 0)
238+++ tests/modeltests/binary/models.py   (revision 0)
239@@ -0,0 +1,18 @@
240+"""
241+BlobField and BinaryField tests
242+
243+"""
244+
245+from django.db import models
246+
247+# Create your models here.
248+class Document(models.Model):
249+    title = models.CharField(max_length=50)
250+    description = models.TextField()
251+    document = models.BlobField()
252+
253+class BinaryFieldTest(models.Model):
254+    title = models.CharField(max_length=20)
255+    binfield = models.BinaryField(max_length=20)
256+
257+