Ticket #9319: models.py

File models.py, 28.7 KB (added by ctao, 6 years ago)
Line 
1"""
2Helper functions for creating Form classes from Django models
3and database field objects.
4"""
5
6from django.utils.encoding import smart_unicode
7from django.utils.datastructures import SortedDict
8from django.utils.text import get_text_list, capfirst
9from django.utils.translation import ugettext_lazy as _
10
11from util import ValidationError, ErrorList
12from forms import BaseForm, get_declared_fields
13from fields import Field, ChoiceField, IntegerField, EMPTY_VALUES
14from widgets import Select, SelectMultiple, HiddenInput, MultipleHiddenInput
15from widgets import media_property
16from formsets import BaseFormSet, formset_factory, DELETION_FIELD_NAME
17
18__all__ = (
19    'ModelForm', 'BaseModelForm', 'model_to_dict', 'fields_for_model',
20    'save_instance', 'form_for_fields', 'ModelChoiceField',
21    'ModelMultipleChoiceField',
22)
23
24
25def save_instance(form, instance, fields=None, fail_message='saved',
26                  commit=True, exclude=None):
27    """
28    Saves bound Form ``form``'s cleaned_data into model instance ``instance``.
29
30    If commit=True, then the changes to ``instance`` will be saved to the
31    database. Returns ``instance``.
32    """
33    from django.db import models
34    opts = instance._meta
35    if form.errors:
36        raise ValueError("The %s could not be %s because the data didn't"
37                         " validate." % (opts.object_name, fail_message))
38    cleaned_data = form.cleaned_data
39    for f in opts.fields:
40        if not f.editable or isinstance(f, models.AutoField) \
41                or not f.name in cleaned_data:
42            continue
43        if fields and f.name not in fields:
44            continue
45        if exclude and f.name in exclude:
46            continue
47        f.save_form_data(instance, cleaned_data[f.name])
48    # Wrap up the saving of m2m data as a function.
49    def save_m2m():
50        opts = instance._meta
51        cleaned_data = form.cleaned_data
52        for f in opts.many_to_many:
53            if fields and f.name not in fields:
54                continue
55            if f.name in cleaned_data:
56                f.save_form_data(instance, cleaned_data[f.name])
57    if commit:
58        # If we are committing, save the instance and the m2m data immediately.
59        instance.save()
60        save_m2m()
61    else:
62        # We're not committing. Add a method to the form to allow deferred
63        # saving of m2m data.
64        form.save_m2m = save_m2m
65    return instance
66
67def make_model_save(model, fields, fail_message):
68    """Returns the save() method for a Form."""
69    def save(self, commit=True):
70        return save_instance(self, model(), fields, fail_message, commit)
71    return save
72
73def make_instance_save(instance, fields, fail_message):
74    """Returns the save() method for a Form."""
75    def save(self, commit=True):
76        return save_instance(self, instance, fields, fail_message, commit)
77    return save
78
79def form_for_fields(field_list):
80    """
81    Returns a Form class for the given list of Django database field instances.
82    """
83    fields = SortedDict([(f.name, f.formfield())
84                         for f in field_list if f.editable])
85    return type('FormForFields', (BaseForm,), {'base_fields': fields})
86
87
88# ModelForms #################################################################
89
90def model_to_dict(instance, fields=None, exclude=None):
91    """
92    Returns a dict containing the data in ``instance`` suitable for passing as
93    a Form's ``initial`` keyword argument.
94
95    ``fields`` is an optional list of field names. If provided, only the named
96    fields will be included in the returned dict.
97
98    ``exclude`` is an optional list of field names. If provided, the named
99    fields will be excluded from the returned dict, even if they are listed in
100    the ``fields`` argument.
101    """
102    # avoid a circular import
103    from django.db.models.fields.related import ManyToManyField, OneToOneField
104    opts = instance._meta
105    data = {}
106    for f in opts.fields + opts.many_to_many:
107        if not f.editable:
108            continue
109        if fields and not f.name in fields:
110            continue
111        if exclude and f.name in exclude:
112            continue
113        if isinstance(f, ManyToManyField):
114            # If the object doesn't have a primry key yet, just use an empty
115            # list for its m2m fields. Calling f.value_from_object will raise
116            # an exception.
117            if instance.pk is None:
118                data[f.name] = []
119            else:
120                # MultipleChoiceWidget needs a list of pks, not object instances.
121                data[f.name] = [obj.pk for obj in f.value_from_object(instance)]
122        else:
123            data[f.name] = f.value_from_object(instance)
124    return data
125
126def fields_for_model(model, fields=None, exclude=None, formfield_callback=lambda f: f.formfield()):
127    """
128    Returns a ``SortedDict`` containing form fields for the given model.
129
130    ``fields`` is an optional list of field names. If provided, only the named
131    fields will be included in the returned fields.
132
133    ``exclude`` is an optional list of field names. If provided, the named
134    fields will be excluded from the returned fields, even if they are listed
135    in the ``fields`` argument.
136    """
137    # TODO: if fields is provided, it would be nice to return fields in that order
138    field_list = []
139    opts = model._meta
140    for f in opts.fields + opts.many_to_many:
141        if not f.editable:
142            continue
143        if fields and not f.name in fields:
144            continue
145        if exclude and f.name in exclude:
146            continue
147        formfield = formfield_callback(f)
148        if formfield:
149            field_list.append((f.name, formfield))
150    return SortedDict(field_list)
151
152class ModelFormOptions(object):
153    def __init__(self, options=None):
154        self.model = getattr(options, 'model', None)
155        self.fields = getattr(options, 'fields', None)
156        self.exclude = getattr(options, 'exclude', None)
157
158
159class ModelFormMetaclass(type):
160    def __new__(cls, name, bases, attrs):
161        formfield_callback = attrs.pop('formfield_callback',
162                lambda f: f.formfield())
163        try:
164            parents = [b for b in bases if issubclass(b, ModelForm)]
165        except NameError:
166            # We are defining ModelForm itself.
167            parents = None
168        declared_fields = get_declared_fields(bases, attrs, False)
169        new_class = super(ModelFormMetaclass, cls).__new__(cls, name, bases,
170                attrs)
171        if not parents:
172            return new_class
173
174        if 'media' not in attrs:
175            new_class.media = media_property(new_class)
176        opts = new_class._meta = ModelFormOptions(getattr(new_class, 'Meta', None))
177        if opts.model:
178            # If a model is defined, extract form fields from it.
179            fields = fields_for_model(opts.model, opts.fields,
180                                      opts.exclude, formfield_callback)
181            # Override default model fields with any custom declared ones
182            # (plus, include all the other declared fields).
183            fields.update(declared_fields)
184        else:
185            fields = declared_fields
186        new_class.declared_fields = declared_fields
187        new_class.base_fields = fields
188        return new_class
189
190class BaseModelForm(BaseForm):
191    def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
192                 initial=None, error_class=ErrorList, label_suffix=':',
193                 empty_permitted=False, instance=None):
194        opts = self._meta
195        if instance is None:
196            # if we didn't get an instance, instantiate a new one
197            self.instance = opts.model()
198            object_data = {}
199        else:
200            self.instance = instance
201            object_data = model_to_dict(instance, opts.fields, opts.exclude)
202        # if initial was provided, it should override the values from instance
203        if initial is not None:
204            object_data.update(initial)
205        super(BaseModelForm, self).__init__(data, files, auto_id, prefix, object_data,
206                                            error_class, label_suffix, empty_permitted)
207    def clean(self):
208        self.validate_unique()
209        return self.cleaned_data
210
211    def validate_unique(self):
212        from django.db.models.fields import FieldDoesNotExist
213
214        # Gather a list of checks to perform. Since this is a ModelForm, some
215        # fields may have been excluded; we can't perform a unique check on a
216        # form that is missing fields involved in that check.
217        unique_checks = []
218        for check in self.instance._meta.unique_together[:]:
219            fields_on_form = [field for field in check if field in self.fields]
220            if len(fields_on_form) == len(check):
221                unique_checks.append(check)
222           
223        form_errors = []
224       
225        # Gather a list of checks for fields declared as unique and add them to
226        # the list of checks. Again, skip fields not on the form.
227        for name, field in self.fields.items():
228            try:
229                f = self.instance._meta.get_field_by_name(name)[0]
230            except FieldDoesNotExist:
231                # This is an extra field that's not on the ModelForm, ignore it
232                continue
233            # MySQL can't handle ... WHERE pk IS NULL, so make sure we
234            # don't generate queries of that form.
235            is_null_pk = f.primary_key and self.cleaned_data[name] is None
236            if name in self.cleaned_data and f.unique and not is_null_pk:
237                unique_checks.append((name,))
238               
239        # Don't run unique checks on fields that already have an error.
240        unique_checks = [check for check in unique_checks if not [x in self._errors for x in check if x in self._errors]]
241       
242        for unique_check in unique_checks:
243            # Try to look up an existing object with the same values as this
244            # object's values for all the unique field.
245           
246            lookup_kwargs = {}
247            print '------------------------------------'
248            print unique_check
249            for field_name in unique_check:
250                print '========================================================'
251                print self.cleaned_data
252                lookup_kwargs[field_name] = self.cleaned_data[field_name]
253           
254            qs = self.instance.__class__._default_manager.filter(**lookup_kwargs)
255
256            # Exclude the current object from the query if we are editing an
257            # instance (as opposed to creating a new one)
258            if self.instance.pk is not None:
259                qs = qs.exclude(pk=self.instance.pk)
260               
261            # This cute trick with extra/values is the most efficient way to
262            # tell if a particular query returns any results.
263            if qs.extra(select={'a': 1}).values('a').order_by():
264                model_name = capfirst(self.instance._meta.verbose_name)
265               
266                # A unique field
267                if len(unique_check) == 1:
268                    field_name = unique_check[0]
269                    field_label = self.fields[field_name].label
270                    # Insert the error into the error dict, very sneaky
271                    self._errors[field_name] = ErrorList([
272                        _(u"%(model_name)s with this %(field_label)s already exists.") % \
273                        {'model_name': unicode(model_name),
274                         'field_label': unicode(field_label)}
275                    ])
276                # unique_together
277                else:
278                    field_labels = [self.fields[field_name].label for field_name in unique_check]
279                    field_labels = get_text_list(field_labels, _('and'))
280                    form_errors.append(
281                        _(u"%(model_name)s with this %(field_label)s already exists.") % \
282                        {'model_name': unicode(model_name),
283                         'field_label': unicode(field_labels)}
284                    )
285               
286                # Remove the data from the cleaned_data dict since it was invalid
287                #for field_name in unique_check:
288                #    del self.cleaned_data[field_name]
289       
290        if form_errors:
291            # Raise the unique together errors since they are considered form-wide.
292            raise ValidationError(form_errors)
293
294    def save(self, commit=True):
295        """
296        Saves this ``form``'s cleaned_data into model instance
297        ``self.instance``.
298
299        If commit=True, then the changes to ``instance`` will be saved to the
300        database. Returns ``instance``.
301        """
302        if self.instance.pk is None:
303            fail_message = 'created'
304        else:
305            fail_message = 'changed'
306        return save_instance(self, self.instance, self._meta.fields, fail_message, commit)
307
308class ModelForm(BaseModelForm):
309    __metaclass__ = ModelFormMetaclass
310
311def modelform_factory(model, form=ModelForm, fields=None, exclude=None,
312                       formfield_callback=lambda f: f.formfield()):
313    # HACK: we should be able to construct a ModelForm without creating
314    # and passing in a temporary inner class
315    class Meta:
316        pass
317    setattr(Meta, 'model', model)
318    setattr(Meta, 'fields', fields)
319    setattr(Meta, 'exclude', exclude)
320    class_name = model.__name__ + 'Form'
321    return ModelFormMetaclass(class_name, (form,), {'Meta': Meta,
322                              'formfield_callback': formfield_callback})
323
324
325# ModelFormSets ##############################################################
326
327class BaseModelFormSet(BaseFormSet):
328    """
329    A ``FormSet`` for editing a queryset and/or adding new objects to it.
330    """
331    model = None
332
333    def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
334                 queryset=None, **kwargs):
335        self.queryset = queryset
336        defaults = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix}
337        defaults['initial'] = [model_to_dict(obj) for obj in self.get_queryset()]
338        defaults.update(kwargs)
339        super(BaseModelFormSet, self).__init__(**defaults)
340
341    def _construct_form(self, i, **kwargs):
342        if i < self._initial_form_count:
343            kwargs['instance'] = self.get_queryset()[i]
344        return super(BaseModelFormSet, self)._construct_form(i, **kwargs)
345
346    def get_queryset(self):
347        if not hasattr(self, '_queryset'):
348            if self.queryset is not None:
349                qs = self.queryset
350            else:
351                qs = self.model._default_manager.get_query_set()
352            if self.max_num > 0:
353                self._queryset = qs[:self.max_num]
354            else:
355                self._queryset = qs
356        return self._queryset
357
358    def save_new(self, form, commit=True):
359        """Saves and returns a new model instance for the given form."""
360        return save_instance(form, self.model(), exclude=[self._pk_field.name], commit=commit)
361
362    def save_existing(self, form, instance, commit=True):
363        """Saves and returns an existing model instance for the given form."""
364        return save_instance(form, instance, exclude=[self._pk_field.name], commit=commit)
365
366    def save(self, commit=True):
367        """Saves model instances for every form, adding and changing instances
368        as necessary, and returns the list of instances.
369        """
370        if not commit:
371            self.saved_forms = []
372            def save_m2m():
373                for form in self.saved_forms:
374                    form.save_m2m()
375            self.save_m2m = save_m2m
376        return self.save_existing_objects(commit) + self.save_new_objects(commit)
377
378    def save_existing_objects(self, commit=True):
379        self.changed_objects = []
380        self.deleted_objects = []
381        if not self.get_queryset():
382            return []
383
384        # Put the objects from self.get_queryset into a dict so they are easy to lookup by pk
385        existing_objects = {}
386        for obj in self.get_queryset():
387            existing_objects[obj.pk] = obj
388        saved_instances = []
389        for form in self.initial_forms:
390            obj = existing_objects[form.cleaned_data[self._pk_field.name]]
391            if self.can_delete and form.cleaned_data[DELETION_FIELD_NAME]:
392                self.deleted_objects.append(obj)
393                obj.delete()
394            else:
395                if form.changed_data:
396                    self.changed_objects.append((obj, form.changed_data))
397                    saved_instances.append(self.save_existing(form, obj, commit=commit))
398                    if not commit:
399                        self.saved_forms.append(form)
400        return saved_instances
401
402    def save_new_objects(self, commit=True):
403        self.new_objects = []
404        for form in self.extra_forms:
405            if not form.has_changed():
406                continue
407            # If someone has marked an add form for deletion, don't save the
408            # object.
409            if self.can_delete and form.cleaned_data[DELETION_FIELD_NAME]:
410                continue
411            self.new_objects.append(self.save_new(form, commit=commit))
412            if not commit:
413                self.saved_forms.append(form)
414        return self.new_objects
415
416    def add_fields(self, form, index):
417        """Add a hidden field for the object's primary key."""
418        from django.db.models import AutoField
419        self._pk_field = pk = self.model._meta.pk
420        if pk.auto_created or isinstance(pk, AutoField):
421            form.fields[self._pk_field.name] = IntegerField(required=False, widget=HiddenInput)
422        super(BaseModelFormSet, self).add_fields(form, index)
423
424def modelformset_factory(model, form=ModelForm, formfield_callback=lambda f: f.formfield(),
425                         formset=BaseModelFormSet,
426                         extra=1, can_delete=False, can_order=False,
427                         max_num=0, fields=None, exclude=None):
428    """
429    Returns a FormSet class for the given Django model class.
430    """
431    form = modelform_factory(model, form=form, fields=fields, exclude=exclude,
432                             formfield_callback=formfield_callback)
433    FormSet = formset_factory(form, formset, extra=extra, max_num=max_num,
434                              can_order=can_order, can_delete=can_delete)
435    FormSet.model = model
436    return FormSet
437
438
439# InlineFormSets #############################################################
440
441class BaseInlineFormSet(BaseModelFormSet):
442    """A formset for child objects related to a parent."""
443    def __init__(self, data=None, files=None, instance=None,
444                 save_as_new=False, prefix=None):
445        from django.db.models.fields.related import RelatedObject
446        self.instance = instance
447        self.save_as_new = save_as_new
448        # is there a better way to get the object descriptor?
449        self.rel_name = RelatedObject(self.fk.rel.to, self.model, self.fk).get_accessor_name()
450        super(BaseInlineFormSet, self).__init__(data, files, prefix=prefix or self.rel_name)
451
452    def _construct_forms(self):
453        if self.save_as_new:
454            self._total_form_count = self._initial_form_count
455            self._initial_form_count = 0
456        super(BaseInlineFormSet, self)._construct_forms()
457
458    def _construct_form(self, i, **kwargs):
459        form = super(BaseInlineFormSet, self)._construct_form(i, **kwargs)
460        if self.save_as_new:
461            # Remove the primary key from the form's data, we are only
462            # creating new instances
463            form.data[form.add_prefix(self._pk_field.name)] = None
464        return form
465
466    def get_queryset(self):
467        """
468        Returns this FormSet's queryset, but restricted to children of
469        self.instance
470        """
471        kwargs = {self.fk.name: self.instance}
472        return self.model._default_manager.filter(**kwargs)
473
474    def save_new(self, form, commit=True):
475        kwargs = {self.fk.get_attname(): self.instance.pk}
476        new_obj = self.model(**kwargs)
477        return save_instance(form, new_obj, exclude=[self._pk_field.name], commit=commit)
478   
479    def add_fields(self, form, index):
480        super(BaseInlineFormSet, self).add_fields(form, index)
481        if self._pk_field == self.fk:
482            form.fields[self._pk_field.name] = IntegerField(required=False, widget=HiddenInput)
483
484def _get_foreign_key(parent_model, model, fk_name=None):
485    """
486    Finds and returns the ForeignKey from model to parent if there is one.
487    If fk_name is provided, assume it is the name of the ForeignKey field.
488    """
489    # avoid circular import
490    from django.db.models import ForeignKey
491    opts = model._meta
492    if fk_name:
493        fks_to_parent = [f for f in opts.fields if f.name == fk_name]
494        if len(fks_to_parent) == 1:
495            fk = fks_to_parent[0]
496            if not isinstance(fk, ForeignKey) or \
497                    (fk.rel.to != parent_model and
498                     fk.rel.to not in parent_model._meta.get_parent_list()):
499                raise Exception("fk_name '%s' is not a ForeignKey to %s" % (fk_name, parent_model))
500        elif len(fks_to_parent) == 0:
501            raise Exception("%s has no field named '%s'" % (model, fk_name))
502    else:
503        # Try to discover what the ForeignKey from model to parent_model is
504        fks_to_parent = [
505            f for f in opts.fields
506            if isinstance(f, ForeignKey)
507            and (f.rel.to == parent_model
508                or f.rel.to in parent_model._meta.get_parent_list())
509        ]
510        if len(fks_to_parent) == 1:
511            fk = fks_to_parent[0]
512        elif len(fks_to_parent) == 0:
513            raise Exception("%s has no ForeignKey to %s" % (model, parent_model))
514        else:
515            raise Exception("%s has more than 1 ForeignKey to %s" % (model, parent_model))
516    return fk
517
518
519def inlineformset_factory(parent_model, model, form=ModelForm,
520                          formset=BaseInlineFormSet, fk_name=None,
521                          fields=None, exclude=None,
522                          extra=3, can_order=False, can_delete=True, max_num=0,
523                          formfield_callback=lambda f: f.formfield()):
524    """
525    Returns an ``InlineFormSet`` for the given kwargs.
526
527    You must provide ``fk_name`` if ``model`` has more than one ``ForeignKey``
528    to ``parent_model``.
529    """
530    fk = _get_foreign_key(parent_model, model, fk_name=fk_name)
531    # enforce a max_num=1 when the foreign key to the parent model is unique.
532    if fk.unique:
533        max_num = 1
534    if exclude is not None:
535        exclude.append(fk.name)
536    else:
537        exclude = [fk.name]
538    kwargs = {
539        'form': form,
540        'formfield_callback': formfield_callback,
541        'formset': formset,
542        'extra': extra,
543        'can_delete': can_delete,
544        'can_order': can_order,
545        'fields': fields,
546        'exclude': exclude,
547        'max_num': max_num,
548    }
549    FormSet = modelformset_factory(model, **kwargs)
550    FormSet.fk = fk
551    return FormSet
552
553
554# Fields #####################################################################
555
556class ModelChoiceIterator(object):
557    def __init__(self, field):
558        self.field = field
559        self.queryset = field.queryset
560
561    def __iter__(self):
562        if self.field.empty_label is not None:
563            yield (u"", self.field.empty_label)
564        if self.field.cache_choices:
565            if self.field.choice_cache is None:
566                self.field.choice_cache = [
567                    self.choice(obj) for obj in self.queryset.all()
568                ]
569            for choice in self.field.choice_cache:
570                yield choice
571        else:
572            for obj in self.queryset.all():
573                yield self.choice(obj)
574
575    def choice(self, obj):
576        if self.field.to_field_name:
577            # FIXME: The try..except shouldn't be necessary here. But this is
578            # going in just before 1.0, so I want to be careful. Will check it
579            # out later.
580            try:
581                key = getattr(obj, self.field.to_field_name).pk
582            except AttributeError:
583                key = getattr(obj, self.field.to_field_name)
584        else:
585            key = obj.pk
586        return (key, self.field.label_from_instance(obj))
587
588
589class ModelChoiceField(ChoiceField):
590    """A ChoiceField whose choices are a model QuerySet."""
591    # This class is a subclass of ChoiceField for purity, but it doesn't
592    # actually use any of ChoiceField's implementation.
593    default_error_messages = {
594        'invalid_choice': _(u'Select a valid choice. That choice is not one of'
595                            u' the available choices.'),
596    }
597
598    def __init__(self, queryset, empty_label=u"---------", cache_choices=False,
599                 required=True, widget=None, label=None, initial=None,
600                 help_text=None, to_field_name=None, *args, **kwargs):
601        self.empty_label = empty_label
602        self.cache_choices = cache_choices
603
604        # Call Field instead of ChoiceField __init__() because we don't need
605        # ChoiceField.__init__().
606        Field.__init__(self, required, widget, label, initial, help_text,
607                       *args, **kwargs)
608        self.queryset = queryset
609        self.choice_cache = None
610        self.to_field_name = to_field_name
611
612    def _get_queryset(self):
613        return self._queryset
614
615    def _set_queryset(self, queryset):
616        self._queryset = queryset
617        self.widget.choices = self.choices
618
619    queryset = property(_get_queryset, _set_queryset)
620
621    # this method will be used to create object labels by the QuerySetIterator.
622    # Override it to customize the label.
623    def label_from_instance(self, obj):
624        """
625        This method is used to convert objects into strings; it's used to
626        generate the labels for the choices presented by this object. Subclasses
627        can override this method to customize the display of the choices.
628        """
629        return smart_unicode(obj)
630
631    def _get_choices(self):
632        # If self._choices is set, then somebody must have manually set
633        # the property self.choices. In this case, just return self._choices.
634        if hasattr(self, '_choices'):
635            return self._choices
636
637        # Otherwise, execute the QuerySet in self.queryset to determine the
638        # choices dynamically. Return a fresh QuerySetIterator that has not been
639        # consumed. Note that we're instantiating a new QuerySetIterator *each*
640        # time _get_choices() is called (and, thus, each time self.choices is
641        # accessed) so that we can ensure the QuerySet has not been consumed. This
642        # construct might look complicated but it allows for lazy evaluation of
643        # the queryset.
644        return ModelChoiceIterator(self)
645
646    choices = property(_get_choices, ChoiceField._set_choices)
647
648    def clean(self, value):
649        Field.clean(self, value)
650        if value in EMPTY_VALUES:
651            return None
652        try:
653            key = self.to_field_name or 'pk'
654            value = self.queryset.get(**{key: value})
655        except self.queryset.model.DoesNotExist:
656            raise ValidationError(self.error_messages['invalid_choice'])
657        return value
658
659class ModelMultipleChoiceField(ModelChoiceField):
660    """A MultipleChoiceField whose choices are a model QuerySet."""
661    widget = SelectMultiple
662    hidden_widget = MultipleHiddenInput
663    default_error_messages = {
664        'list': _(u'Enter a list of values.'),
665        'invalid_choice': _(u'Select a valid choice. %s is not one of the'
666                            u' available choices.'),
667    }
668
669    def __init__(self, queryset, cache_choices=False, required=True,
670                 widget=None, label=None, initial=None,
671                 help_text=None, *args, **kwargs):
672        super(ModelMultipleChoiceField, self).__init__(queryset, None,
673            cache_choices, required, widget, label, initial, help_text,
674            *args, **kwargs)
675
676    def clean(self, value):
677        if self.required and not value:
678            raise ValidationError(self.error_messages['required'])
679        elif not self.required and not value:
680            return []
681        if not isinstance(value, (list, tuple)):
682            raise ValidationError(self.error_messages['list'])
683        final_values = []
684        for val in value:
685            try:
686                obj = self.queryset.get(pk=val)
687            except self.queryset.model.DoesNotExist:
688                raise ValidationError(self.error_messages['invalid_choice'] % val)
689            else:
690                final_values.append(obj)
691        return final_values
Back to Top