Ticket #2417: BLOB_and_Binary_fields_patch.txt

File BLOB_and_Binary_fields_patch.txt, 9.8 KB (added by alex@…, 16 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+
Back to Top