Django

Code

root/django/tags/releases/1.0/django/forms/models.py

Revision 8957, 27.8 kB (checked in by mtredinnick, 10 months ago)

Fixed #8841 -- Fixed a case of ForeignKeys? to models constructed with
inheritance.

This patch is uglier than it needs to be (see comment in patch) to ensure no
accidental bug is introduced just before 1.0. We'll clean it up later.

  • Property svn:eol-style set to native
Line 
1 """
2 Helper functions for creating Form classes from Django models
3 and database field objects.
4 """
5
6 from django.utils.encoding import smart_unicode
7 from django.utils.datastructures import SortedDict
8 from django.utils.text import get_text_list, capfirst
9 from django.utils.translation import ugettext_lazy as _
10
11 from util import ValidationError, ErrorList
12 from forms import BaseForm, get_declared_fields
13 from fields import Field, ChoiceField, IntegerField, EMPTY_VALUES
14 from widgets import Select, SelectMultiple, HiddenInput, MultipleHiddenInput
15 from widgets import media_property
16 from 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
25 def 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
67 def 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
73 def 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
79 def 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
90 def 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
126 def 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
152 class 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
159 class 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
190 class 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             for field_name in unique_check:
248                 lookup_kwargs[field_name] = self.cleaned_data[field_name]
249            
250             qs = self.instance.__class__._default_manager.filter(**lookup_kwargs)
251
252             # Exclude the current object from the query if we are editing an
253             # instance (as opposed to creating a new one)
254             if self.instance.pk is not None:
255                 qs = qs.exclude(pk=self.instance.pk)
256                
257             # This cute trick with extra/values is the most efficient way to
258             # tell if a particular query returns any results.
259             if qs.extra(select={'a': 1}).values('a').order_by():
260                 model_name = capfirst(self.instance._meta.verbose_name)
261                
262                 # A unique field
263                 if len(unique_check) == 1:
264                     field_name = unique_check[0]
265                     field_label = self.fields[field_name].label
266                     # Insert the error into the error dict, very sneaky
267                     self._errors[field_name] = ErrorList([
268                         _(u"%(model_name)s with this %(field_label)s already exists.") % \
269                         {'model_name': unicode(model_name),
270                          'field_label': unicode(field_label)}
271                     ])
272                 # unique_together
273                 else:
274                     field_labels = [self.fields[field_name].label for field_name in unique_check]
275                     field_labels = get_text_list(field_labels, _('and'))
276                     form_errors.append(
277                         _(u"%(model_name)s with this %(field_label)s already exists.") % \
278                         {'model_name': unicode(model_name),
279                          'field_label': unicode(field_labels)}
280                     )
281                
282                 # Remove the data from the cleaned_data dict since it was invalid
283                 for field_name in unique_check:
284                     del self.cleaned_data[field_name]
285        
286         if form_errors:
287             # Raise the unique together errors since they are considered form-wide.
288             raise ValidationError(form_errors)
289
290     def save(self, commit=True):
291         """
292         Saves this ``form``'s cleaned_data into model instance
293         ``self.instance``.
294
295         If commit=True, then the changes to ``instance`` will be saved to the
296         database. Returns ``instance``.
297         """
298         if self.instance.pk is None:
299             fail_message = 'created'
300         else:
301             fail_message = 'changed'
302         return save_instance(self, self.instance, self._meta.fields, fail_message, commit)
303
304 class ModelForm(BaseModelForm):
305     __metaclass__ = ModelFormMetaclass
306
307 def modelform_factory(model, form=ModelForm, fields=None, exclude=None,
308                        formfield_callback=lambda f: f.formfield()):
309     # HACK: we should be able to construct a ModelForm without creating
310     # and passing in a temporary inner class
311     class Meta:
312         pass
313     setattr(Meta, 'model', model)
314     setattr(Meta, 'fields', fields)
315     setattr(Meta, 'exclude', exclude)
316     class_name = model.__name__ + 'Form'
317     return ModelFormMetaclass(class_name, (form,), {'Meta': Meta,
318                               'formfield_callback': formfield_callback})
319
320
321 # ModelFormSets ##############################################################
322
323 class BaseModelFormSet(BaseFormSet):
324     """
325     A ``FormSet`` for editing a queryset and/or adding new objects to it.
326     """
327     model = None
328
329     def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
330                  queryset=None, **kwargs):
331         self.queryset = queryset
332         defaults = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix}
333         defaults['initial'] = [model_to_dict(obj) for obj in self.get_queryset()]
334         defaults.update(kwargs)
335         super(BaseModelFormSet, self).__init__(**defaults)
336
337     def _construct_form(self, i, **kwargs):
338         if i < self._initial_form_count:
339             kwargs['instance'] = self.get_queryset()[i]
340         return super(BaseModelFormSet, self)._construct_form(i, **kwargs)
341
342     def get_queryset(self):
343         if not hasattr(self, '_queryset'):
344             if self.queryset is not None:
345                 qs = self.queryset
346             else:
347                 qs = self.model._default_manager.get_query_set()
348             if self.max_num > 0:
349                 self._queryset = qs[:self.max_num]
350             else:
351                 self._queryset = qs
352         return self._queryset
353
354     def save_new(self, form, commit=True):
355         """Saves and returns a new model instance for the given form."""
356         return save_instance(form, self.model(), exclude=[self._pk_field.name], commit=commit)
357
358     def save_existing(self, form, instance, commit=True):
359         """Saves and returns an existing model instance for the given form."""
360         return save_instance(form, instance, exclude=[self._pk_field.name], commit=commit)
361
362     def save(self, commit=True):
363         """Saves model instances for every form, adding and changing instances
364         as necessary, and returns the list of instances.
365         """
366         if not commit:
367             self.saved_forms = []
368             def save_m2m():
369                 for form in self.saved_forms:
370                     form.save_m2m()
371             self.save_m2m = save_m2m
372         return self.save_existing_objects(commit) + self.save_new_objects(commit)
373
374     def save_existing_objects(self, commit=True):
375         self.changed_objects = []
376         self.deleted_objects = []
377         if not self.get_queryset():
378             return []
379
380         # Put the objects from self.get_queryset into a dict so they are easy to lookup by pk
381         existing_objects = {}
382         for obj in self.get_queryset():
383             existing_objects[obj.pk] = obj
384         saved_instances = []
385         for form in self.initial_forms:
386             obj = existing_objects[form.cleaned_data[self._pk_field.name]]
387             if self.can_delete and form.cleaned_data[DELETION_FIELD_NAME]:
388                 self.deleted_objects.append(obj)
389                 obj.delete()
390             else:
391                 if form.changed_data:
392                     self.changed_objects.append((obj, form.changed_data))
393                     saved_instances.append(self.save_existing(form, obj, commit=commit))
394                     if not commit:
395                         self.saved_forms.append(form)
396         return saved_instances
397
398     def save_new_objects(self, commit=True):
399         self.new_objects = []
400         for form in self.extra_forms:
401             if not form.has_changed():
402                 continue
403             # If someone has marked an add form for deletion, don't save the
404             # object.
405             if self.can_delete and form.cleaned_data[DELETION_FIELD_NAME]:
406                 continue
407             self.new_objects.append(self.save_new(form, commit=commit))
408             if not commit:
409                 self.saved_forms.append(form)
410         return self.new_objects
411
412     def add_fields(self, form, index):
413         """Add a hidden field for the object's primary key."""
414         from django.db.models import AutoField
415         self._pk_field = pk = self.model._meta.pk
416         if pk.auto_created or isinstance(pk, AutoField):
417             form.fields[self._pk_field.name] = IntegerField(required=False, widget=HiddenInput)
418         super(BaseModelFormSet, self).add_fields(form, index)
419
420 def modelformset_factory(model, form=ModelForm, formfield_callback=lambda f: f.formfield(),
421                          formset=BaseModelFormSet,
422                          extra=1, can_delete=False, can_order=False,
423                          max_num=0, fields=None, exclude=None):
424     """
425     Returns a FormSet class for the given Django model class.
426     """
427     form = modelform_factory(model, form=form, fields=fields, exclude=exclude,
428                              formfield_callback=formfield_callback)
429     FormSet = formset_factory(form, formset, extra=extra, max_num=max_num,
430                               can_order=can_order, can_delete=can_delete)
431     FormSet.model = model
432     return FormSet
433
434
435 # InlineFormSets #############################################################
436
437 class BaseInlineFormSet(BaseModelFormSet):
438     """A formset for child objects related to a parent."""
439     def __init__(self, data=None, files=None, instance=None,
440                  save_as_new=False, prefix=None):
441         from django.db.models.fields.related import RelatedObject
442         self.instance = instance
443         self.save_as_new = save_as_new
444         # is there a better way to get the object descriptor?
445         self.rel_name = RelatedObject(self.fk.rel.to, self.model, self.fk).get_accessor_name()
446         super(BaseInlineFormSet, self).__init__(data, files, prefix=prefix or self.rel_name)
447
448     def _construct_forms(self):
449         if self.save_as_new:
450             self._total_form_count = self._initial_form_count
451             self._initial_form_count = 0
452         super(BaseInlineFormSet, self)._construct_forms()
453
454     def _construct_form(self, i, **kwargs):
455         form = super(BaseInlineFormSet, self)._construct_form(i, **kwargs)
456         if self.save_as_new:
457             # Remove the primary key from the form's data, we are only
458             # creating new instances
459             form.data[form.add_prefix(self._pk_field.name)] = None
460         return form
461
462     def get_queryset(self):
463         """
464         Returns this FormSet's queryset, but restricted to children of
465         self.instance
466         """
467         kwargs = {self.fk.name: self.instance}
468         return self.model._default_manager.filter(**kwargs)
469
470     def save_new(self, form, commit=True):
471         kwargs = {self.fk.get_attname(): self.instance.pk}
472         new_obj = self.model(**kwargs)
473         return save_instance(form, new_obj, exclude=[self._pk_field.name], commit=commit)
474    
475     def add_fields(self, form, index):
476         super(BaseInlineFormSet, self).add_fields(form, index)
477         if self._pk_field == self.fk:
478             form.fields[self._pk_field.name] = IntegerField(required=False, widget=HiddenInput)
479
480 def _get_foreign_key(parent_model, model, fk_name=None):
481     """
482     Finds and returns the ForeignKey from model to parent if there is one.
483     If fk_name is provided, assume it is the name of the ForeignKey field.
484     """
485     # avoid circular import
486     from django.db.models import ForeignKey
487     opts = model._meta
488     if fk_name:
489         fks_to_parent = [f for f in opts.fields if f.name == fk_name]
490         if len(fks_to_parent) == 1:
491             fk = fks_to_parent[0]
492             if not isinstance(fk, ForeignKey) or \
493                     (fk.rel.to != parent_model and
494                      fk.rel.to not in parent_model._meta.get_parent_list()):
495                 raise Exception("fk_name '%s' is not a ForeignKey to %s" % (fk_name, parent_model))
496         elif len(fks_to_parent) == 0:
497             raise Exception("%s has no field named '%s'" % (model, fk_name))
498     else:
499         # Try to discover what the ForeignKey from model to parent_model is
500         fks_to_parent = [
501             f for f in opts.fields
502             if isinstance(f, ForeignKey)
503             and (f.rel.to == parent_model
504                 or f.rel.to in parent_model._meta.get_parent_list())
505         ]
506         if len(fks_to_parent) == 1:
507             fk = fks_to_parent[0]
508         elif len(fks_to_parent) == 0:
509             raise Exception("%s has no ForeignKey to %s" % (model, parent_model))
510         else:
511             raise Exception("%s has more than 1 ForeignKey to %s" % (model, parent_model))
512     return fk
513
514
515 def inlineformset_factory(parent_model, model, form=ModelForm,
516                           formset=BaseInlineFormSet, fk_name=None,
517                           fields=None, exclude=None,
518                           extra=3, can_order=False, can_delete=True, max_num=0,
519                           formfield_callback=lambda f: f.formfield()):
520     """
521     Returns an ``InlineFormSet`` for the given kwargs.
522
523     You must provide ``fk_name`` if ``model`` has more than one ``ForeignKey``
524     to ``parent_model``.
525     """
526     fk = _get_foreign_key(parent_model, model, fk_name=fk_name)
527     # enforce a max_num=1 when the foreign key to the parent model is unique.
528     if fk.unique:
529         max_num = 1
530     if exclude is not None:
531         exclude.append(fk.name)
532     else:
533         exclude = [fk.name]
534     kwargs = {
535         'form': form,
536         'formfield_callback': formfield_callback,
537         'formset': formset,
538         'extra': extra,
539         'can_delete': can_delete,
540         'can_order': can_order,
541         'fields': fields,
542         'exclude': exclude,
543         'max_num': max_num,
544     }
545     FormSet = modelformset_factory(model, **kwargs)
546     FormSet.fk = fk
547     return FormSet
548
549
550 # Fields #####################################################################
551
552 class ModelChoiceIterator(object):
553     def __init__(self, field):
554         self.field = field
555         self.queryset = field.queryset
556
557     def __iter__(self):
558         if self.field.empty_label is not None:
559             yield (u"", self.field.empty_label)
560         if self.field.cache_choices:
561             if self.field.choice_cache is None:
562                 self.field.choice_cache = [
563                     self.choice(obj) for obj in self.queryset.all()
564                 ]
565             for choice in self.field.choice_cache:
566                 yield choice
567         else:
568             for obj in self.queryset.all():
569                 yield self.choice(obj)
570
571     def choice(self, obj):
572         if self.field.to_field_name:
573             # FIXME: The try..except shouldn't be necessary here. But this is
574             # going in just before 1.0, so I want to be careful. Will check it
575             # out later.
576             try:
577                 key = getattr(obj, self.field.to_field_name).pk
578             except AttributeError:
579                 key = getattr(obj, self.field.to_field_name)
580         else:
581             key = obj.pk
582         return (key, self.field.label_from_instance(obj))
583
584
585 class ModelChoiceField(ChoiceField):
586     """A ChoiceField whose choices are a model QuerySet."""
587     # This class is a subclass of ChoiceField for purity, but it doesn't
588     # actually use any of ChoiceField's implementation.
589     default_error_messages = {
590         'invalid_choice': _(u'Select a valid choice. That choice is not one of'
591                             u' the available choices.'),
592     }
593
594     def __init__(self, queryset, empty_label=u"---------", cache_choices=False,
595                  required=True, widget=None, label=None, initial=None,
596                  help_text=None, to_field_name=None, *args, **kwargs):
597         self.empty_label = empty_label
598         self.cache_choices = cache_choices
599
600         # Call Field instead of ChoiceField __init__() because we don't need
601         # ChoiceField.__init__().
602         Field.__init__(self, required, widget, label, initial, help_text,
603                        *args, **kwargs)
604         self.queryset = queryset
605         self.choice_cache = None
606         self.to_field_name = to_field_name
607
608     def _get_queryset(self):
609         return self._queryset
610
611     def _set_queryset(self, queryset):
612         self._queryset = queryset
613         self.widget.choices = self.choices
614
615     queryset = property(_get_queryset, _set_queryset)
616
617     # this method will be used to create object labels by the QuerySetIterator.
618     # Override it to customize the label.
619     def label_from_instance(self, obj):
620         """
621         This method is used to convert objects into strings; it's used to
622         generate the labels for the choices presented by this object. Subclasses
623         can override this method to customize the display of the choices.
624         """
625         return smart_unicode(obj)
626
627     def _get_choices(self):
628         # If self._choices is set, then somebody must have manually set
629         # the property self.choices. In this case, just return self._choices.
630         if hasattr(self, '_choices'):
631             return self._choices
632
633         # Otherwise, execute the QuerySet in self.queryset to determine the
634         # choices dynamically. Return a fresh QuerySetIterator that has not been
635         # consumed. Note that we're instantiating a new QuerySetIterator *each*
636         # time _get_choices() is called (and, thus, each time self.choices is
637         # accessed) so that we can ensure the QuerySet has not been consumed. This
638         # construct might look complicated but it allows for lazy evaluation of
639         # the queryset.
640         return ModelChoiceIterator(self)
641
642     choices = property(_get_choices, ChoiceField._set_choices)
643
644     def clean(self, value):
645         Field.clean(self, value)
646         if value in EMPTY_VALUES:
647             return None
648         try:
649             key = self.to_field_name or 'pk'
650             value = self.queryset.get(**{key: value})
651         except self.queryset.model.DoesNotExist:
652             raise ValidationError(self.error_messages['invalid_choice'])
653         return value
654
655 class ModelMultipleChoiceField(ModelChoiceField):
656     """A MultipleChoiceField whose choices are a model QuerySet."""
657     widget = SelectMultiple
658     hidden_widget = MultipleHiddenInput
659     default_error_messages = {
660         'list': _(u'Enter a list of values.'),
661         'invalid_choice': _(u'Select a valid choice. %s is not one of the'
662                             u' available choices.'),
663     }
664
665     def __init__(self, queryset, cache_choices=False, required=True,
666                  widget=None, label=None, initial=None,
667                  help_text=None, *args, **kwargs):
668         super(ModelMultipleChoiceField, self).__init__(queryset, None,
669             cache_choices, required, widget, label, initial, help_text,
670             *args, **kwargs)
671
672     def clean(self, value):
673         if self.required and not value:
674             raise ValidationError(self.error_messages['required'])
675         elif not self.required and not value:
676             return []
677         if not isinstance(value, (list, tuple)):
678             raise ValidationError(self.error_messages['list'])
679         final_values = []
680         for val in value:
681             try:
682                 obj = self.queryset.get(pk=val)
683             except self.queryset.model.DoesNotExist:
684                 raise ValidationError(self.error_messages['invalid_choice'] % val)
685             else:
686                 final_values.append(obj)
687         return final_values
Note: See TracBrowser for help on using the browser.