From babfe78494028415b0e5f74ec2ca9b66506e8d34 Mon Sep 17 00:00:00 2001 From: Gary Wilson Jr Date: Tue, 13 Nov 2007 14:36:29 +0000 Subject: [PATCH] Fixed #4787, #5913 -- Updating the queryset on a `ModelChoiceField` or `ModelMultipleChoiceField` now updates its widget's choices. The clean methods for `ModelChoiceField` and `ModelMultipleChoiceField` were changed to only allow choices in the specified queryset (instead of allowing all choices returned by the queryset model's default manager). git-svn-id: http://code.djangoproject.com/svn/django/trunk@6670 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/newforms/models.py | 14 ++++++++--- tests/modeltests/model_forms/models.py | 32 ++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/django/newforms/models.py b/django/newforms/models.py index 269166c5d5..c86b9b3a42 100644 --- a/django/newforms/models.py +++ b/django/newforms/models.py @@ -155,14 +155,22 @@ class ModelChoiceField(ChoiceField): def __init__(self, queryset, empty_label=u"---------", cache_choices=False, required=True, widget=Select, label=None, initial=None, help_text=None): - self.queryset = queryset self.empty_label = empty_label self.cache_choices = cache_choices # Call Field instead of ChoiceField __init__() because we don't need # ChoiceField.__init__(). Field.__init__(self, required, widget, label, initial, help_text) + self.queryset = queryset + + def _get_queryset(self): + return self._queryset + + def _set_queryset(self, queryset): + self._queryset = queryset self.widget.choices = self.choices + queryset = property(_get_queryset, _set_queryset) + def _get_choices(self): # If self._choices is set, then somebody must have manually set # the property self.choices. In this case, just return self._choices. @@ -190,7 +198,7 @@ class ModelChoiceField(ChoiceField): if value in ('', None): return None try: - value = self.queryset.model._default_manager.get(pk=value) + value = self.queryset.get(pk=value) except self.queryset.model.DoesNotExist: raise ValidationError(ugettext(u'Select a valid choice. That' u' choice is not one of the' @@ -217,7 +225,7 @@ class ModelMultipleChoiceField(ModelChoiceField): final_values = [] for val in value: try: - obj = self.queryset.model._default_manager.get(pk=val) + obj = self.queryset.get(pk=val) except self.queryset.model.DoesNotExist: raise ValidationError(ugettext(u'Select a valid choice. %s is' u' not one of the available' diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py index 66865976c8..e4e230c98d 100644 --- a/tests/modeltests/model_forms/models.py +++ b/tests/modeltests/model_forms/models.py @@ -440,6 +440,8 @@ the data in the database when the form is instantiated. >>> from django.newforms import ModelChoiceField, ModelMultipleChoiceField >>> f = ModelChoiceField(Category.objects.all()) +>>> list(f.choices) +[(u'', u'---------'), (1, u'Entertainment'), (2, u"It's a test"), (3, u'Third'), (4, u'Fourth')] >>> f.clean('') Traceback (most recent call last): ... @@ -485,9 +487,23 @@ Traceback (most recent call last): ... ValidationError: [u'Select a valid choice. That choice is not one of the available choices.'] +# queryset can be changed after the field is created. +>>> f.queryset = Category.objects.exclude(name='Fourth') +>>> list(f.choices) +[(u'', u'---------'), (1, u'Entertainment'), (2, u"It's a test"), (3, u'Third')] +>>> f.clean(3) + +>>> f.clean(4) +Traceback (most recent call last): +... +ValidationError: [u'Select a valid choice. That choice is not one of the available choices.'] + + # ModelMultipleChoiceField #################################################### >>> f = ModelMultipleChoiceField(Category.objects.all()) +>>> list(f.choices) +[(1, u'Entertainment'), (2, u"It's a test"), (3, u'Third'), (4, u'Fourth')] >>> f.clean(None) Traceback (most recent call last): ... @@ -552,6 +568,22 @@ Traceback (most recent call last): ... ValidationError: [u'Select a valid choice. 10 is not one of the available choices.'] +# queryset can be changed after the field is created. +>>> f.queryset = Category.objects.exclude(name='Fourth') +>>> list(f.choices) +[(1, u'Entertainment'), (2, u"It's a test"), (3, u'Third')] +>>> f.clean([3]) +[] +>>> f.clean([4]) +Traceback (most recent call last): +... +ValidationError: [u'Select a valid choice. 4 is not one of the available choices.'] +>>> f.clean(['3', '4']) +Traceback (most recent call last): +... +ValidationError: [u'Select a valid choice. 4 is not one of the available choices.'] + + # PhoneNumberField ############################################################ >>> PhoneNumberForm = form_for_model(PhoneNumber)