Code

Ticket #9245: 9245.2.diff

File 9245.2.diff, 6.2 KB (added by badri, 6 years ago)
Line 
1Index: django/db/models/fields/__init__.py
2===================================================================
3--- django/db/models/fields/__init__.py (revision 9111)
4+++ django/db/models/fields/__init__.py (working copy)
5@@ -313,9 +313,11 @@
6             include_blank = self.blank or not (self.has_default() or 'initial' in kwargs)
7             defaults['choices'] = self.get_choices(include_blank=include_blank)
8             defaults['coerce'] = self.to_python
9-            if self.null:
10-                defaults['empty_value'] = None
11-            form_class = forms.TypedChoiceField
12+            if form_class in (forms.CharField, forms.BooleanField,forms.IntegerField, forms.RegexField,
13+                              forms.TypedChoiceField, forms.NullBooleanField):
14+                 form_class = forms.TypedChoiceField
15+                 if self.null:
16+                    defaults['empty_value'] = None
17             # Many of the subclass-specific formfield arguments (min_value,
18             # max_value) don't apply for choice fields, so be sure to only pass
19             # the values that TypedChoiceField will understand.
20Index: tests/regressiontests/forms/tests.py
21===================================================================
22--- tests/regressiontests/forms/tests.py        (revision 9111)
23+++ tests/regressiontests/forms/tests.py        (working copy)
24@@ -30,6 +30,7 @@
25 from widgets import tests as widgets_tests
26 from formsets import tests as formset_tests
27 from media import media_tests
28+from forms import custom_form_field_tests
29 
30 __test__ = {
31     'extra_tests': extra_tests,
32@@ -63,6 +64,7 @@
33     'media_tests': media_tests,
34     'util_tests': util_tests,
35     'widgets_tests': widgets_tests,
36+    'custom_form_field_tests': custom_form_field_tests,
37 }
38 
39 if __name__ == "__main__":
40Index: tests/regressiontests/forms/models.py
41===================================================================
42--- tests/regressiontests/forms/models.py       (revision 9111)
43+++ tests/regressiontests/forms/models.py       (working copy)
44@@ -5,6 +5,7 @@
45 # Can't import as "forms" due to implementation details in the test suite (the
46 # current file is called "forms" and is already imported).
47 from django import forms as django_forms
48+from django.utils.encoding import force_unicode
49 
50 class BoundaryModel(models.Model):
51     positive_integer = models.PositiveIntegerField(null=True, blank=True)
52@@ -24,6 +25,71 @@
53 class FileForm(django_forms.Form):
54     file1 = django_forms.FileField()
55 
56+# models for custom form fields, regress for #9245
57+from django.forms import fields
58+class CustomFormField(fields.TypedChoiceField):
59+    def __init__(self, *args, **kwargs):
60+        super(CustomFormField, self).__init__(*args, **kwargs)
61+
62+    def clean(self, value):
63+        return super(CustomFormField, self).clean(value)
64+
65+# a trivial object to be stored in db
66+class Small(object):
67+    def __init__(self, first, second):
68+        self.first, self.second = first, second
69+
70+    def __unicode__(self):
71+        return u'%s%s' % (force_unicode(self.first), force_unicode(self.second))
72+
73+    def __str__(self):
74+        return unicode(self).encode('utf-8')
75+
76+# create a custom field upon 'Small' and associate with a custom form field
77+class SmallField(models.Field):
78+    __metaclass__ = models.SubfieldBase
79+
80+    def __init__(self, *args, **kwargs):
81+        kwargs['max_length'] = 2
82+        super(SmallField, self).__init__(*args, **kwargs)
83+
84+    def get_internal_type(self):
85+        return 'CharField'
86+
87+    def to_python(self, value):
88+        if isinstance(value, Small):
89+            return value
90+        return Small(value[0], value[1])
91+
92+    def get_db_prep_save(self, value):
93+        return unicode(value)
94+
95+    def get_db_prep_lookup(self, lookup_type, value):
96+        if lookup_type == 'exact':
97+            return force_unicode(value)
98+        if lookup_type == 'in':
99+            return [force_unicode(v) for v in value]
100+        if lookup_type == 'isnull':
101+            return []
102+        raise FieldError('Invalid lookup type: %r' % lookup_type)
103+
104+    def formfield(self, **kwargs):
105+        return super(SmallField, self).formfield(form_class = CustomFormField, **kwargs)
106+        return super(SmallField, self).formfield(**kwargs)
107+
108+# use SmallField in a model
109+class MyModel(models.Model):
110+    name = models.CharField(max_length=10)
111+    MY_CHOICES  = (
112+        ('AB', 'ab'),
113+        ('CD', 'cd'),
114+        ('EF', 'ef'),
115+    )
116+    data = SmallField('small field',choices = MY_CHOICES)
117+
118+    def __unicode__(self):
119+        return force_unicode(self.name)
120+
121 __test__ = {'API_TESTS': """
122 >>> from django.forms.models import ModelForm
123 >>> from django.core.files.uploadedfile import SimpleUploadedFile
124Index: tests/regressiontests/forms/forms.py
125===================================================================
126--- tests/regressiontests/forms/forms.py        (revision 9111)
127+++ tests/regressiontests/forms/forms.py        (working copy)
128@@ -1750,3 +1750,37 @@
129 True
130 
131 """
132+custom_form_field_tests = r"""
133+>>> from regressiontests.forms.models import MyModel
134+>>> from regressiontests.forms.models import Small
135+>>> s = Small('A', 'B')
136+>>> MyModel.objects.create(pk=1, name='abc', data = s)
137+<MyModel: abc>
138+>>> from django.forms import ModelForm
139+>>> class MyModelForm(ModelForm):
140+...     class Meta:
141+...         model = MyModel
142+...
143+>>> mymodel_form = MyModelForm(instance = MyModel.objects.get(id=1))
144+>>> print mymodel_form['data']
145+<select name="data" id="id_data">
146+<option value="">---------</option>
147+<option value="AB" selected="selected">ab</option>
148+<option value="CD">cd</option>
149+<option value="EF">ef</option>
150+</select>
151+>>> from regressiontests.forms.models import SmallField
152+>>> small_field = SmallField('a simple small field', choices = MyModel.MY_CHOICES)
153+>>> small_field.formfield().__class__
154+<class 'regressiontests.forms.models.CustomFormField'>
155+>>> small_field = SmallField('small field without choices')
156+>>> small_field.formfield().__class__
157+<class 'regressiontests.forms.models.CustomFormField'>
158+>>> from django.db import models
159+>>> regular_field = models.CharField(max_length=2, choices = MyModel.MY_CHOICES)
160+>>> regular_field.formfield().__class__
161+<class 'django.forms.fields.TypedChoiceField'>
162+>>> regular_field = models.CharField(max_length=10)
163+>>> regular_field.formfield().__class__
164+<class 'django.forms.fields.CharField'>
165+"""