Ticket #3257: related_choice_field_empty_label.patch

File related_choice_field_empty_label.patch, 7.8 KB (added by Honza Král <Honza.Kral@…>, 12 years ago)

added empty_label kwarg to the field, all tests pass now

  • django/db/models/fields/related.py

     
    553553        setattr(cls, related.get_accessor_name(), ForeignRelatedObjectsDescriptor(related))
    554554
    555555    def formfield(self, **kwargs):
    556         defaults = {'choices': self.get_choices_default(), 'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
     556        defaults = {'queryset': self.rel.to._default_manager.all(), 'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
    557557        defaults.update(kwargs)
    558         return forms.ChoiceField(**defaults)
     558        return forms.ModelChoiceField(**defaults)
    559559
    560560class OneToOneField(RelatedField, IntegerField):
    561561    def __init__(self, to, to_field=None, **kwargs):
     
    619619            cls._meta.one_to_one_field = self
    620620
    621621    def formfield(self, **kwargs):
    622         defaults = {'choices': self.get_choices_default(), 'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
     622        defaults = {'queryset': self.rel.to._default_manager.all(), 'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
    623623        defaults.update(kwargs)
    624         return forms.ChoiceField(**kwargs)
     624        return forms.ModelChoiceField(**kwargs)
    625625
    626626class ManyToManyField(RelatedField, Field):
    627627    def __init__(self, to, **kwargs):
     
    742742        # MultipleChoiceField takes a list of IDs.
    743743        if kwargs.get('initial') is not None:
    744744            kwargs['initial'] = [i._get_pk_val() for i in kwargs['initial']]
    745         defaults = {'choices': self.get_choices_default(), 'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
     745        defaults = {'queryset' : self.rel.to._default_manager.all(), 'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
    746746        defaults.update(kwargs)
    747         return forms.MultipleChoiceField(**defaults)
     747        return forms.ModelMultipleChoiceField(**defaults)
    748748
    749749class ManyToOneRel(object):
    750750    def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None,
  • django/newforms/models.py

     
    44"""
    55
    66from forms import BaseForm, DeclarativeFieldsMetaclass, SortedDictFromList
     7from fields import ChoiceField, MultipleChoiceField
     8from widgets import Select, SelectMultiple
    79
    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')
    912
    1013def model_save(self, commit=True):
    1114    """
     
    3336    for f in opts.fields:
    3437        if isinstance(f, models.AutoField):
    3538            continue
    36         setattr(instance, f.attname, clean_data[f.name])
     39        setattr(instance, f.name, clean_data[f.name])
    3740    if commit:
    3841        instance.save()
    3942        for f in opts.many_to_many:
     
    9699    "Returns a Form class for the given list of Django database field instances."
    97100    fields = SortedDictFromList([(f.name, f.formfield()) for f in field_list])
    98101    return type('FormForFields', (BaseForm,), {'base_fields': fields})
     102
     103class ModelChoiceField(ChoiceField):
     104    def __init__(self, queryset, empty_label=u"---------", **kwargs):
     105        self.model = queryset.model
     106        choices=[(obj._get_pk_val(), str(obj)) for obj in queryset]
     107        if not empty_label is None:
     108            choices = [(u"", empty_label)] + choices
     109        ChoiceField.__init__(self, choices=choices, **kwargs)
     110 
     111    def clean(self, value):
     112        new_value = ChoiceField.clean(self, value)
     113        if not new_value:
     114            return None
     115        try:
     116            new_value = self.model._default_manager.get(pk=new_value)
     117        except:
     118            raise ValidationError(gettext(u'Select a valid choice. %s is not one of the available choices.') % value)
     119        return new_value
     120 
     121class ModelMultipleChoiceField(MultipleChoiceField):
     122    def __init__(self, queryset, **kwargs):
     123        self.model = queryset.model
     124        MultipleChoiceField.__init__(self, choices=[(obj._get_pk_val(), str(obj)) for obj in queryset], **kwargs)
     125 
     126    def clean(self, value):
     127        new_value = MultipleChoiceField.clean(self, value)
     128        if not new_value:
     129            return []
     130        return self.model._default_manager.filter(pk__in=new_value) 
  • tests/modeltests/model_forms/models.py

     
    2424
    2525from django.db import models
    2626
     27class Poll(models.Model):
     28    question = models.CharField(maxlength=200)
     29    def __str__(self):
     30        return "Q: %s " % self.question
     31
    2732class Category(models.Model):
    2833    name = models.CharField(maxlength=20)
    2934    url = models.CharField('The URL', maxlength=40)
     
    281286<Category: Third>
    282287>>> Category.objects.get(id=3)
    283288<Category: Third>
     289
     290# ModelChoiceField #################################################################
     291
     292>>> from django.newforms import *
     293
     294>>> p = Poll(question="Test Question")
     295>>> p.save()
     296>>> p2 = Poll(question="Second Test Question")
     297>>> p2.save()
     298
     299>>> f = ModelChoiceField(Poll.objects.all())
     300>>> f.clean('')
     301Traceback (most recent call last):
     302...
     303ValidationError: [u'This field is required.']
     304>>> f.clean(None)
     305Traceback (most recent call last):
     306...
     307ValidationError: [u'This field is required.']
     308>>> f.clean(0)
     309Traceback (most recent call last):
     310...
     311ValidationError: [u'Select a valid choice. 0 is not one of the available choices.']
     312>>> f.clean(1)
     313<Poll: Q: Test Question >
     314>>> f.clean(2)
     315<Poll: Q: Second Test Question >
     316
     317>>> f = ModelChoiceField(Poll.objects.filter( pk=1 ), required=False)
     318>>> print f.clean('')
     319None
     320>>> f.clean('')
     321>>> f.clean('1')
     322<Poll: Q: Test Question >
     323>>> f.clean('2')
     324Traceback (most recent call last):
     325...
     326ValidationError: [u'Select a valid choice. 2 is not one of the available choices.']
     327
     328# ModelMultipleChoiceField #########################################################
     329
     330>>> f = ModelMultipleChoiceField(Poll.objects.all())
     331>>> f.clean(None)
     332Traceback (most recent call last):
     333...
     334ValidationError: [u'This field is required.']
     335>>> f.clean([])
     336Traceback (most recent call last):
     337...
     338ValidationError: [u'This field is required.']
     339>>> f.clean([1])
     340[<Poll: Q: Test Question >]
     341>>> f.clean([2])
     342[<Poll: Q: Second Test Question >]
     343>>> f.clean(['1'])
     344[<Poll: Q: Test Question >]
     345>>> f.clean(['1', '2'])
     346[<Poll: Q: Test Question >, <Poll: Q: Second Test Question >]
     347>>> f.clean([1, '2'])
     348[<Poll: Q: Test Question >, <Poll: Q: Second Test Question >]
     349>>> f.clean((1, '2'))
     350[<Poll: Q: Test Question >, <Poll: Q: Second Test Question >]
     351>>> f.clean('hello')
     352Traceback (most recent call last):
     353...
     354ValidationError: [u'Enter a list of values.']
     355>>> f = ModelMultipleChoiceField(Poll.objects.all(), required=False)
     356>>> f.clean([])
     357[]
     358>>> f.clean(())
     359[]
     360>>> f.clean(['3'])
     361Traceback (most recent call last):
     362...
     363ValidationError: [u'Select a valid choice. 3 is not one of the available choices.']
     364>>> f.clean(['3', '4'])
     365Traceback (most recent call last):
     366...
     367ValidationError: [u'Select a valid choice. 3 is not one of the available choices.']
     368>>> f.clean(['1', '5'])
     369Traceback (most recent call last):
     370...
     371ValidationError: [u'Select a valid choice. 5 is not one of the available choices.']
    284372"""}
Back to Top