Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #3257 -- Added newforms ModelChoiceField and ModelMultipleChoic…

…eField, which are now used by form_for_model() and form_for_instance(). Thanks for the patch, Honza Kral, floguy@gmail.com and kilian.cavalotti

git-svn-id: http://code.djangoproject.com/svn/django/trunk@4547 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit e56934b9b903535ace50f46d892dab4225b67f61 1 parent 907241e
Adrian Holovaty authored February 20, 2007
12  django/db/models/fields/related.py
@@ -553,9 +553,9 @@ def contribute_to_related_class(self, cls, related):
@@ -619,9 +619,9 @@ def contribute_to_related_class(self, cls, related):
@@ -742,9 +742,9 @@ def formfield(self, **kwargs):
38  django/newforms/models.py
@@ -4,8 +4,11 @@
4 4
 """
5 5
 
6 6
 from forms import BaseForm, DeclarativeFieldsMetaclass, SortedDictFromList
  7
+from fields import ChoiceField, MultipleChoiceField
  8
+from widgets import Select, SelectMultiple
7 9
 
8  
-__all__ = ('save_instance', 'form_for_model', 'form_for_instance', 'form_for_fields')
  10
+__all__ = ('save_instance', 'form_for_model', 'form_for_instance', 'form_for_fields',
  11
+           'ModelChoiceField', 'ModelMultipleChoiceField')
9 12
 
10 13
 def model_save(self, commit=True):
11 14
     """
@@ -33,7 +36,7 @@ def save_instance(form, instance, commit=True):
33 36
     for f in opts.fields:
34 37
         if isinstance(f, models.AutoField):
35 38
             continue
36  
-        setattr(instance, f.attname, clean_data[f.name])
  39
+        setattr(instance, f.name, clean_data[f.name])
37 40
     if commit:
38 41
         instance.save()
39 42
         for f in opts.many_to_many:
@@ -96,3 +99,34 @@ def form_for_fields(field_list):
96 99
     "Returns a Form class for the given list of Django database field instances."
97 100
     fields = SortedDictFromList([(f.name, f.formfield()) for f in field_list])
98 101
     return type('FormForFields', (BaseForm,), {'base_fields': fields})
  102
+
  103
+class ModelChoiceField(ChoiceField):
  104
+    "A ChoiceField whose choices are a model QuerySet."
  105
+    def __init__(self, queryset, empty_label=u"---------", **kwargs):
  106
+        self.model = queryset.model
  107
+        choices = [(obj._get_pk_val(), str(obj)) for obj in queryset]
  108
+        if empty_label is not None:
  109
+            choices = [(u"", empty_label)] + choices
  110
+        ChoiceField.__init__(self, choices=choices, **kwargs)
  111
+
  112
+    def clean(self, value):
  113
+        value = ChoiceField.clean(self, value)
  114
+        if not value:
  115
+            return None
  116
+        try:
  117
+            value = self.model._default_manager.get(pk=value)
  118
+        except self.model.DoesNotExist:
  119
+            raise ValidationError(gettext(u'Select a valid choice. That choice is not one of the available choices.'))
  120
+        return value
  121
+
  122
+class ModelMultipleChoiceField(MultipleChoiceField):
  123
+    "A MultipleChoiceField whose choices are a model QuerySet."
  124
+    def __init__(self, queryset, **kwargs):
  125
+        self.model = queryset.model
  126
+        MultipleChoiceField.__init__(self, choices=[(obj._get_pk_val(), str(obj)) for obj in queryset], **kwargs)
  127
+
  128
+    def clean(self, value):
  129
+        value = MultipleChoiceField.clean(self, value)
  130
+        if not value:
  131
+            return []
  132
+        return self.model._default_manager.filter(pk__in=value)
82  tests/modeltests/model_forms/models.py
@@ -281,4 +281,86 @@ def __str__(self):
281 281
 <Category: Third>
282 282
 >>> Category.objects.get(id=3)
283 283
 <Category: Third>
  284
+
  285
+# ModelChoiceField ############################################################
  286
+
  287
+>>> from django.newforms import ModelChoiceField, ModelMultipleChoiceField
  288
+
  289
+>>> f = ModelChoiceField(Category.objects.all())
  290
+>>> f.clean('')
  291
+Traceback (most recent call last):
  292
+...
  293
+ValidationError: [u'This field is required.']
  294
+>>> f.clean(None)
  295
+Traceback (most recent call last):
  296
+...
  297
+ValidationError: [u'This field is required.']
  298
+>>> f.clean(0)
  299
+Traceback (most recent call last):
  300
+...
  301
+ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
  302
+>>> f.clean(3)
  303
+<Category: Third>
  304
+>>> f.clean(2)
  305
+<Category: It's a test>
  306
+
  307
+>>> f = ModelChoiceField(Category.objects.filter(pk=1), required=False)
  308
+>>> print f.clean('')
  309
+None
  310
+>>> f.clean('')
  311
+>>> f.clean('1')
  312
+<Category: Entertainment>
  313
+>>> f.clean('2')
  314
+Traceback (most recent call last):
  315
+...
  316
+ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
  317
+
  318
+# ModelMultipleChoiceField ####################################################
  319
+
  320
+>>> f = ModelMultipleChoiceField(Category.objects.all())
  321
+>>> f.clean(None)
  322
+Traceback (most recent call last):
  323
+...
  324
+ValidationError: [u'This field is required.']
  325
+>>> f.clean([])
  326
+Traceback (most recent call last):
  327
+...
  328
+ValidationError: [u'This field is required.']
  329
+>>> f.clean([1])
  330
+[<Category: Entertainment>]
  331
+>>> f.clean([2])
  332
+[<Category: It's a test>]
  333
+>>> f.clean(['1'])
  334
+[<Category: Entertainment>]
  335
+>>> f.clean(['1', '2'])
  336
+[<Category: Entertainment>, <Category: It's a test>]
  337
+>>> f.clean([1, '2'])
  338
+[<Category: Entertainment>, <Category: It's a test>]
  339
+>>> f.clean((1, '2'))
  340
+[<Category: Entertainment>, <Category: It's a test>]
  341
+>>> f.clean(['nonexistent'])
  342
+Traceback (most recent call last):
  343
+...
  344
+ValidationError: [u'Select a valid choice. nonexistent is not one of the available choices.']
  345
+>>> f.clean('hello')
  346
+Traceback (most recent call last):
  347
+...
  348
+ValidationError: [u'Enter a list of values.']
  349
+>>> f = ModelMultipleChoiceField(Category.objects.all(), required=False)
  350
+>>> f.clean([])
  351
+[]
  352
+>>> f.clean(())
  353
+[]
  354
+>>> f.clean(['4'])
  355
+Traceback (most recent call last):
  356
+...
  357
+ValidationError: [u'Select a valid choice. 4 is not one of the available choices.']
  358
+>>> f.clean(['3', '4'])
  359
+Traceback (most recent call last):
  360
+...
  361
+ValidationError: [u'Select a valid choice. 4 is not one of the available choices.']
  362
+>>> f.clean(['1', '5'])
  363
+Traceback (most recent call last):
  364
+...
  365
+ValidationError: [u'Select a valid choice. 5 is not one of the available choices.']
284 366
 """}

0 notes on commit e56934b

Please sign in to comment.
Something went wrong with that request. Please try again.