Code

Ticket #2417: BLOB_and_Binary_fields_patch.txt

File BLOB_and_Binary_fields_patch.txt, 9.8 KB (added by alex@…, 6 years ago)

BinaryField, BlobField patch to Django

Line 
1Index: django/db/models/base.py
2===================================================================
3--- django/db/models/base.py    (revision 7996)
4+++ django/db/models/base.py    (working copy)
5@@ -170,7 +170,6 @@
6 
7     def __init__(self, *args, **kwargs):
8         dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs)
9-
10         # There is a rather weird disparity here; if kwargs, it's set, then args
11         # overrides it. It should be one or the other; don't duplicate the work
12         # The reason for the kwargs check is that standard iterator passes in by
13@@ -187,6 +186,8 @@
14             # is *not* consumed. We rely on this, so don't change the order
15             # without changing the logic.
16             for val, field in izip(args, fields_iter):
17+                if field.get_internal_type() in ['BlobField', 'BinaryField']:
18+                    val = buffer(val)
19                 setattr(self, field.attname, val)
20         else:
21             # Slower, kwargs-ready version.
22Index: django/db/models/fields/__init__.py
23===================================================================
24--- django/db/models/fields/__init__.py (revision 7996)
25+++ django/db/models/fields/__init__.py (working copy)
26@@ -157,7 +157,10 @@
27         # exactly which wacky database column type you want to use.
28         data = DictWrapper(self.__dict__, connection.ops.quote_name, "qn_")
29         try:
30+            # print get_creation_module().DATA_TYPES, self.get_internal_type(), data
31+            # print get_creation_module().DATA_TYPES[self.get_internal_type()]
32             return get_creation_module().DATA_TYPES[self.get_internal_type()] % data
33+       
34         except KeyError:
35             return None
36 
37@@ -349,6 +352,22 @@
38     def get_validator_unique_lookup_type(self):
39         return '%s__exact' % self.name
40 
41+    def get_manipulator_new_file_data(self, new_data, rel=False):
42+        """
43+        Return the file data in order to overcome some nasty
44+        corner cases
45+        """
46+        if rel:
47+            val = new_data.get(self.name+"_file", [self.get_default()])
48+            try:
49+                return val[0]
50+            except(IndexError):
51+                return self.get_default()
52+        val = new_data.get(self.name+"_file",self.get_default())
53+        if not self.empty_strings_allowed and val == '' and self.null:
54+            val = None
55+        return val
56+
57     def get_manipulator_new_data(self, new_data, rel=False):
58         """
59         Given the full new_data dictionary (from the manipulator), returns this
60@@ -518,6 +537,37 @@
61         defaults.update(kwargs)
62         return super(CharField, self).formfield(**defaults)
63 
64+class BinaryField(Field):
65+    """Sometimes we have fields that need to store a small amount of binary
66+    data. This is different then a varchar on postgresql at least because it
67+    will not allow fields that are just nul bytes.
68+    """
69+    def get_manipulator_field_objs(self):
70+        # XXX We should probably use a better form field for this. Like
71+        # XXX something that can grok colon-separated hexlify.
72+        #
73+        return [django.forms.TextField]
74+
75+    def get_internal_type(self):
76+        return "BinaryField"
77+
78+
79+class BlobField(Field):
80+    """Sometimes we have fields that need to store a large amounts of binary
81+    data.
82+    """
83+
84+    def get_internal_type(self):
85+        return "BlobField"
86+
87+
88+    def get_manipulator_field_objs(self):
89+        # XXX We should probably use a better form field for this. Like
90+        # XXX something that can grok colon-separated hexlify.
91+        #
92+        return [django.forms.TextField]
93+
94+
95 # TODO: Maybe move this into contrib, because it's specialized.
96 class CommaSeparatedIntegerField(CharField):
97     def get_manipulator_field_objs(self):
98Index: django/db/backends/postgresql/creation.py
99===================================================================
100--- django/db/backends/postgresql/creation.py   (revision 7996)
101+++ django/db/backends/postgresql/creation.py   (working copy)
102@@ -4,6 +4,8 @@
103 # If a column type is set to None, it won't be included in the output.
104 DATA_TYPES = {
105     'AutoField':         'serial',
106+    'BinaryField':       'bytea',
107+    'BlobField':         'bytea',
108     'BooleanField':      'boolean',
109     'CharField':         'varchar(%(max_length)s)',
110     'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
111Index: django/db/backends/sqlite3/creation.py
112===================================================================
113--- django/db/backends/sqlite3/creation.py      (revision 7996)
114+++ django/db/backends/sqlite3/creation.py      (working copy)
115@@ -3,6 +3,8 @@
116 # schema inspection is more useful.
117 DATA_TYPES = {
118     'AutoField':                    'integer',
119+    'BinaryField':                  'BLOB',
120+    'BlobField':                    'BLOB',
121     'BooleanField':                 'bool',
122     'CharField':                    'varchar(%(max_length)s)',
123     'CommaSeparatedIntegerField':   'varchar(%(max_length)s)',
124Index: django/db/backends/mysql/introspection.py
125===================================================================
126--- django/db/backends/mysql/introspection.py   (revision 7996)
127+++ django/db/backends/mysql/introspection.py   (working copy)
128@@ -75,7 +75,7 @@
129     return indexes
130 
131 DATA_TYPES_REVERSE = {
132-    FIELD_TYPE.BLOB: 'TextField',
133+    FIELD_TYPE.BLOB: 'BlobField',
134     FIELD_TYPE.CHAR: 'CharField',
135     FIELD_TYPE.DECIMAL: 'DecimalField',
136     FIELD_TYPE.DATE: 'DateField',
137Index: django/db/backends/mysql/creation.py
138===================================================================
139--- django/db/backends/mysql/creation.py        (revision 7996)
140+++ django/db/backends/mysql/creation.py        (working copy)
141@@ -4,6 +4,8 @@
142 # If a column type is set to None, it won't be included in the output.
143 DATA_TYPES = {
144     'AutoField':         'integer AUTO_INCREMENT',
145+    'BinaryField':       'varbinary(%(max_length)s)',
146+    'BlobField':         'blob',
147     'BooleanField':      'bool',
148     'CharField':         'varchar(%(max_length)s)',
149     'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
150@@ -13,8 +15,8 @@
151     'FileField':         'varchar(%(max_length)s)',
152     'FilePathField':     'varchar(%(max_length)s)',
153     'FloatField':        'double precision',
154+    'IPAddressField':    'char(15)',
155     'IntegerField':      'integer',
156-    'IPAddressField':    'char(15)',
157     'NullBooleanField':  'bool',
158     'OneToOneField':     'integer',
159     'PhoneNumberField':  'varchar(20)',
160Index: django/db/backends/__init__.py
161===================================================================
162--- django/db/backends/__init__.py      (revision 7996)
163+++ django/db/backends/__init__.py      (working copy)
164@@ -146,9 +146,9 @@
165         # Convert params to contain Unicode values.
166         to_unicode = lambda s: force_unicode(s, strings_only=True)
167         if isinstance(params, (list, tuple)):
168-            u_params = tuple([to_unicode(val) for val in params])
169+            u_params = tuple([to_unicode(repr(val)) for val in params])
170         else:
171-            u_params = dict([(to_unicode(k), to_unicode(v)) for k, v in params.items()])
172+            u_params = dict([(to_unicode(k), to_unicode(repr(v))) for k, v in params.items()])
173 
174         return smart_unicode(sql) % u_params
175 
176Index: tests/modeltests/binary/__init__.py
177===================================================================
178Index: tests/modeltests/binary/tests.py
179===================================================================
180--- tests/modeltests/binary/tests.py    (revision 0)
181+++ tests/modeltests/binary/tests.py    (revision 0)
182@@ -0,0 +1,63 @@
183+#!/usr/bin/python
184+# encoding: utf-8
185+
186+from models import Document, BinaryFieldTest
187+
188+import unittest
189+
190+
191+class BlobFieldTests( unittest.TestCase ):
192+   
193+     def test_blob(self):
194+         test_title = u'Hi there! привет!'
195+         test_descr = u'описание документа'
196+
197+         s = ''
198+         for i in range(0,256):
199+              s += chr(i)
200+             
201+         
202+         test_data = buffer(s)
203+         
204+         
205+         doc = Document(title = test_title,
206+                        description = test_descr,
207+                        document = test_data)
208+         doc.save()
209+         doc_id = doc.id
210+         doc = None
211+         doc = Document.objects.get(id=doc_id)
212+         assert doc.title == test_title, type(doc.title)
213+         assert doc.description == test_descr, type(doc.description)
214+         assert doc.document == test_data, type(doc.document)
215+
216+class BinaryFieldTests( unittest.TestCase ):
217+   
218+     def test_binary(self):
219+         test_title = u'Hi there! привет!'
220+
221+         s = ''
222+         for i in range(0,19):
223+              s += chr(i)
224+         test_data = buffer(s)
225+
226+         tst = BinaryFieldTest(title = test_title,
227+                          binfield = test_data)
228+         tst.save()
229+         tst_id = tst.id
230+         tst = None
231+         tst = BinaryFieldTest.objects.get(id=tst_id)
232+         assert tst.title == test_title, type(tst.title)
233+         assert tst.binfield == test_data, type(tst.binfield)
234+                         
235+
236+def test_suite():
237+    return unittest.TestSuite((
238+        unittest.makeSuite(BlobFieldTests),
239+        unittest.makeSuite(BinaryFieldTests)
240+        ))
241+
242+
243+
244+if __name__ == '__main__':
245+    unittest.main(defaultTest='test_suite')
246Index: tests/modeltests/binary/models.py
247===================================================================
248--- tests/modeltests/binary/models.py   (revision 0)
249+++ tests/modeltests/binary/models.py   (revision 0)
250@@ -0,0 +1,18 @@
251+"""
252+BlobField and BinaryField tests
253+
254+"""
255+
256+from django.db import models
257+
258+# Create your models here.
259+class Document(models.Model):
260+    title = models.CharField(max_length=50)
261+    description = models.TextField()
262+    document = models.BlobField()
263+
264+class BinaryFieldTest(models.Model):
265+    title = models.CharField(max_length=20)
266+    binfield = models.BinaryField(max_length=20)
267+
268+