web/lib/django/forms/models.py
changeset 0 0d40e90630ef
child 29 cc9b7e14412b
equal deleted inserted replaced
-1:000000000000 0:0d40e90630ef
       
     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, force_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 _, ugettext
       
    10 
       
    11 from util import ValidationError, ErrorList
       
    12 from forms import BaseForm, get_declared_fields, NON_FIELD_ERRORS
       
    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 try:
       
    19     set
       
    20 except NameError:
       
    21     from sets import Set as set     # Python 2.3 fallback
       
    22 
       
    23 __all__ = (
       
    24     'ModelForm', 'BaseModelForm', 'model_to_dict', 'fields_for_model',
       
    25     'save_instance', 'form_for_fields', 'ModelChoiceField',
       
    26     'ModelMultipleChoiceField',
       
    27 )
       
    28 
       
    29 
       
    30 def save_instance(form, instance, fields=None, fail_message='saved',
       
    31                   commit=True, exclude=None):
       
    32     """
       
    33     Saves bound Form ``form``'s cleaned_data into model instance ``instance``.
       
    34 
       
    35     If commit=True, then the changes to ``instance`` will be saved to the
       
    36     database. Returns ``instance``.
       
    37     """
       
    38     from django.db import models
       
    39     opts = instance._meta
       
    40     if form.errors:
       
    41         raise ValueError("The %s could not be %s because the data didn't"
       
    42                          " validate." % (opts.object_name, fail_message))
       
    43     cleaned_data = form.cleaned_data
       
    44     file_field_list = []
       
    45     for f in opts.fields:
       
    46         if not f.editable or isinstance(f, models.AutoField) \
       
    47                 or not f.name in cleaned_data:
       
    48             continue
       
    49         if fields and f.name not in fields:
       
    50             continue
       
    51         if exclude and f.name in exclude:
       
    52             continue
       
    53         # OneToOneField doesn't allow assignment of None. Guard against that
       
    54         # instead of allowing it and throwing an error.
       
    55         if isinstance(f, models.OneToOneField) and cleaned_data[f.name] is None:
       
    56             continue
       
    57         # Defer saving file-type fields until after the other fields, so a
       
    58         # callable upload_to can use the values from other fields.
       
    59         if isinstance(f, models.FileField):
       
    60             file_field_list.append(f)
       
    61         else:
       
    62             f.save_form_data(instance, cleaned_data[f.name])
       
    63 
       
    64     for f in file_field_list:
       
    65         f.save_form_data(instance, cleaned_data[f.name])
       
    66 
       
    67     # Wrap up the saving of m2m data as a function.
       
    68     def save_m2m():
       
    69         opts = instance._meta
       
    70         cleaned_data = form.cleaned_data
       
    71         for f in opts.many_to_many:
       
    72             if fields and f.name not in fields:
       
    73                 continue
       
    74             if f.name in cleaned_data:
       
    75                 f.save_form_data(instance, cleaned_data[f.name])
       
    76     if commit:
       
    77         # If we are committing, save the instance and the m2m data immediately.
       
    78         instance.save()
       
    79         save_m2m()
       
    80     else:
       
    81         # We're not committing. Add a method to the form to allow deferred
       
    82         # saving of m2m data.
       
    83         form.save_m2m = save_m2m
       
    84     return instance
       
    85 
       
    86 def make_model_save(model, fields, fail_message):
       
    87     """Returns the save() method for a Form."""
       
    88     def save(self, commit=True):
       
    89         return save_instance(self, model(), fields, fail_message, commit)
       
    90     return save
       
    91 
       
    92 def make_instance_save(instance, fields, fail_message):
       
    93     """Returns the save() method for a Form."""
       
    94     def save(self, commit=True):
       
    95         return save_instance(self, instance, fields, fail_message, commit)
       
    96     return save
       
    97 
       
    98 def form_for_fields(field_list):
       
    99     """
       
   100     Returns a Form class for the given list of Django database field instances.
       
   101     """
       
   102     fields = SortedDict([(f.name, f.formfield())
       
   103                          for f in field_list if f.editable])
       
   104     return type('FormForFields', (BaseForm,), {'base_fields': fields})
       
   105 
       
   106 
       
   107 # ModelForms #################################################################
       
   108 
       
   109 def model_to_dict(instance, fields=None, exclude=None):
       
   110     """
       
   111     Returns a dict containing the data in ``instance`` suitable for passing as
       
   112     a Form's ``initial`` keyword argument.
       
   113 
       
   114     ``fields`` is an optional list of field names. If provided, only the named
       
   115     fields will be included in the returned dict.
       
   116 
       
   117     ``exclude`` is an optional list of field names. If provided, the named
       
   118     fields will be excluded from the returned dict, even if they are listed in
       
   119     the ``fields`` argument.
       
   120     """
       
   121     # avoid a circular import
       
   122     from django.db.models.fields.related import ManyToManyField, OneToOneField
       
   123     opts = instance._meta
       
   124     data = {}
       
   125     for f in opts.fields + opts.many_to_many:
       
   126         if not f.editable:
       
   127             continue
       
   128         if fields and not f.name in fields:
       
   129             continue
       
   130         if exclude and f.name in exclude:
       
   131             continue
       
   132         if isinstance(f, ManyToManyField):
       
   133             # If the object doesn't have a primry key yet, just use an empty
       
   134             # list for its m2m fields. Calling f.value_from_object will raise
       
   135             # an exception.
       
   136             if instance.pk is None:
       
   137                 data[f.name] = []
       
   138             else:
       
   139                 # MultipleChoiceWidget needs a list of pks, not object instances.
       
   140                 data[f.name] = [obj.pk for obj in f.value_from_object(instance)]
       
   141         else:
       
   142             data[f.name] = f.value_from_object(instance)
       
   143     return data
       
   144 
       
   145 def fields_for_model(model, fields=None, exclude=None, formfield_callback=lambda f: f.formfield()):
       
   146     """
       
   147     Returns a ``SortedDict`` containing form fields for the given model.
       
   148 
       
   149     ``fields`` is an optional list of field names. If provided, only the named
       
   150     fields will be included in the returned fields.
       
   151 
       
   152     ``exclude`` is an optional list of field names. If provided, the named
       
   153     fields will be excluded from the returned fields, even if they are listed
       
   154     in the ``fields`` argument.
       
   155     """
       
   156     field_list = []
       
   157     opts = model._meta
       
   158     for f in opts.fields + opts.many_to_many:
       
   159         if not f.editable:
       
   160             continue
       
   161         if fields and not f.name in fields:
       
   162             continue
       
   163         if exclude and f.name in exclude:
       
   164             continue
       
   165         formfield = formfield_callback(f)
       
   166         if formfield:
       
   167             field_list.append((f.name, formfield))
       
   168     field_dict = SortedDict(field_list)
       
   169     if fields:
       
   170         field_dict = SortedDict([(f, field_dict.get(f)) for f in fields if (not exclude) or (exclude and f not in exclude)])
       
   171     return field_dict
       
   172 
       
   173 class ModelFormOptions(object):
       
   174     def __init__(self, options=None):
       
   175         self.model = getattr(options, 'model', None)
       
   176         self.fields = getattr(options, 'fields', None)
       
   177         self.exclude = getattr(options, 'exclude', None)
       
   178 
       
   179 
       
   180 class ModelFormMetaclass(type):
       
   181     def __new__(cls, name, bases, attrs):
       
   182         formfield_callback = attrs.pop('formfield_callback',
       
   183                 lambda f: f.formfield())
       
   184         try:
       
   185             parents = [b for b in bases if issubclass(b, ModelForm)]
       
   186         except NameError:
       
   187             # We are defining ModelForm itself.
       
   188             parents = None
       
   189         declared_fields = get_declared_fields(bases, attrs, False)
       
   190         new_class = super(ModelFormMetaclass, cls).__new__(cls, name, bases,
       
   191                 attrs)
       
   192         if not parents:
       
   193             return new_class
       
   194 
       
   195         if 'media' not in attrs:
       
   196             new_class.media = media_property(new_class)
       
   197         opts = new_class._meta = ModelFormOptions(getattr(new_class, 'Meta', None))
       
   198         if opts.model:
       
   199             # If a model is defined, extract form fields from it.
       
   200             fields = fields_for_model(opts.model, opts.fields,
       
   201                                       opts.exclude, formfield_callback)
       
   202             # Override default model fields with any custom declared ones
       
   203             # (plus, include all the other declared fields).
       
   204             fields.update(declared_fields)
       
   205         else:
       
   206             fields = declared_fields
       
   207         new_class.declared_fields = declared_fields
       
   208         new_class.base_fields = fields
       
   209         return new_class
       
   210 
       
   211 class BaseModelForm(BaseForm):
       
   212     def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
       
   213                  initial=None, error_class=ErrorList, label_suffix=':',
       
   214                  empty_permitted=False, instance=None):
       
   215         opts = self._meta
       
   216         if instance is None:
       
   217             # if we didn't get an instance, instantiate a new one
       
   218             self.instance = opts.model()
       
   219             object_data = {}
       
   220         else:
       
   221             self.instance = instance
       
   222             object_data = model_to_dict(instance, opts.fields, opts.exclude)
       
   223         # if initial was provided, it should override the values from instance
       
   224         if initial is not None:
       
   225             object_data.update(initial)
       
   226         super(BaseModelForm, self).__init__(data, files, auto_id, prefix, object_data,
       
   227                                             error_class, label_suffix, empty_permitted)
       
   228 
       
   229     def clean(self):
       
   230         self.validate_unique()
       
   231         return self.cleaned_data
       
   232 
       
   233     def validate_unique(self):
       
   234         unique_checks, date_checks = self._get_unique_checks()
       
   235         form_errors = []
       
   236         bad_fields = set()
       
   237 
       
   238         field_errors, global_errors = self._perform_unique_checks(unique_checks)
       
   239         bad_fields.union(field_errors)
       
   240         form_errors.extend(global_errors)
       
   241 
       
   242         field_errors, global_errors = self._perform_date_checks(date_checks)
       
   243         bad_fields.union(field_errors)
       
   244         form_errors.extend(global_errors)
       
   245 
       
   246         for field_name in bad_fields:
       
   247             del self.cleaned_data[field_name]
       
   248         if form_errors:
       
   249             # Raise the unique together errors since they are considered
       
   250             # form-wide.
       
   251             raise ValidationError(form_errors)
       
   252 
       
   253     def _get_unique_checks(self):
       
   254         from django.db.models.fields import FieldDoesNotExist, Field as ModelField
       
   255 
       
   256         # Gather a list of checks to perform. We only perform unique checks
       
   257         # for fields present and not None in cleaned_data.  Since this is a
       
   258         # ModelForm, some fields may have been excluded; we can't perform a unique
       
   259         # check on a form that is missing fields involved in that check.  It also does
       
   260         # not make sense to check data that didn't validate, and since NULL does not
       
   261         # equal NULL in SQL we should not do any unique checking for NULL values.
       
   262         unique_checks = []
       
   263         # these are checks for the unique_for_<date/year/month>
       
   264         date_checks = []
       
   265         for check in self.instance._meta.unique_together[:]:
       
   266             fields_on_form = [field for field in check if self.cleaned_data.get(field) is not None]
       
   267             if len(fields_on_form) == len(check):
       
   268                 unique_checks.append(check)
       
   269 
       
   270         # Gather a list of checks for fields declared as unique and add them to
       
   271         # the list of checks. Again, skip empty fields and any that did not validate.
       
   272         for name in self.fields:
       
   273             try:
       
   274                 f = self.instance._meta.get_field_by_name(name)[0]
       
   275             except FieldDoesNotExist:
       
   276                 # This is an extra field that's not on the ModelForm, ignore it
       
   277                 continue
       
   278             if not isinstance(f, ModelField):
       
   279                 # This is an extra field that happens to have a name that matches,
       
   280                 # for example, a related object accessor for this model.  So
       
   281                 # get_field_by_name found it, but it is not a Field so do not proceed
       
   282                 # to use it as if it were.
       
   283                 continue
       
   284             if self.cleaned_data.get(name) is None:
       
   285                 continue
       
   286             if f.unique:
       
   287                 unique_checks.append((name,))
       
   288             if f.unique_for_date and self.cleaned_data.get(f.unique_for_date) is not None:
       
   289                 date_checks.append(('date', name, f.unique_for_date))
       
   290             if f.unique_for_year and self.cleaned_data.get(f.unique_for_year) is not None:
       
   291                 date_checks.append(('year', name, f.unique_for_year))
       
   292             if f.unique_for_month and self.cleaned_data.get(f.unique_for_month) is not None:
       
   293                 date_checks.append(('month', name, f.unique_for_month))
       
   294         return unique_checks, date_checks
       
   295 
       
   296 
       
   297     def _perform_unique_checks(self, unique_checks):
       
   298         bad_fields = set()
       
   299         form_errors = []
       
   300 
       
   301         for unique_check in unique_checks:
       
   302             # Try to look up an existing object with the same values as this
       
   303             # object's values for all the unique field.
       
   304 
       
   305             lookup_kwargs = {}
       
   306             for field_name in unique_check:
       
   307                 lookup_value = self.cleaned_data[field_name]
       
   308                 # ModelChoiceField will return an object instance rather than
       
   309                 # a raw primary key value, so convert it to a pk value before
       
   310                 # using it in a lookup.
       
   311                 if isinstance(self.fields[field_name], ModelChoiceField):
       
   312                     lookup_value =  lookup_value.pk
       
   313                 lookup_kwargs[str(field_name)] = lookup_value
       
   314 
       
   315             qs = self.instance.__class__._default_manager.filter(**lookup_kwargs)
       
   316 
       
   317             # Exclude the current object from the query if we are editing an
       
   318             # instance (as opposed to creating a new one)
       
   319             if self.instance.pk is not None:
       
   320                 qs = qs.exclude(pk=self.instance.pk)
       
   321 
       
   322             # This cute trick with extra/values is the most efficient way to
       
   323             # tell if a particular query returns any results.
       
   324             if qs.extra(select={'a': 1}).values('a').order_by():
       
   325                 if len(unique_check) == 1:
       
   326                     self._errors[unique_check[0]] = ErrorList([self.unique_error_message(unique_check)])
       
   327                 else:
       
   328                     form_errors.append(self.unique_error_message(unique_check))
       
   329 
       
   330                 # Mark these fields as needing to be removed from cleaned data
       
   331                 # later.
       
   332                 for field_name in unique_check:
       
   333                     bad_fields.add(field_name)
       
   334         return bad_fields, form_errors
       
   335 
       
   336     def _perform_date_checks(self, date_checks):
       
   337         bad_fields = set()
       
   338         for lookup_type, field, unique_for in date_checks:
       
   339             lookup_kwargs = {}
       
   340             # there's a ticket to add a date lookup, we can remove this special
       
   341             # case if that makes it's way in
       
   342             if lookup_type == 'date':
       
   343                 date = self.cleaned_data[unique_for]
       
   344                 lookup_kwargs['%s__day' % unique_for] = date.day
       
   345                 lookup_kwargs['%s__month' % unique_for] = date.month
       
   346                 lookup_kwargs['%s__year' % unique_for] = date.year
       
   347             else:
       
   348                 lookup_kwargs['%s__%s' % (unique_for, lookup_type)] = getattr(self.cleaned_data[unique_for], lookup_type)
       
   349             lookup_kwargs[field] = self.cleaned_data[field]
       
   350 
       
   351             qs = self.instance.__class__._default_manager.filter(**lookup_kwargs)
       
   352             # Exclude the current object from the query if we are editing an
       
   353             # instance (as opposed to creating a new one)
       
   354             if self.instance.pk is not None:
       
   355                 qs = qs.exclude(pk=self.instance.pk)
       
   356 
       
   357             # This cute trick with extra/values is the most efficient way to
       
   358             # tell if a particular query returns any results.
       
   359             if qs.extra(select={'a': 1}).values('a').order_by():
       
   360                 self._errors[field] = ErrorList([
       
   361                     self.date_error_message(lookup_type, field, unique_for)
       
   362                 ])
       
   363                 bad_fields.add(field)
       
   364         return bad_fields, []
       
   365 
       
   366     def date_error_message(self, lookup_type, field, unique_for):
       
   367         return _(u"%(field_name)s must be unique for %(date_field)s %(lookup)s.") % {
       
   368             'field_name': unicode(self.fields[field].label),
       
   369             'date_field': unicode(self.fields[unique_for].label),
       
   370             'lookup': lookup_type,
       
   371         }
       
   372 
       
   373     def unique_error_message(self, unique_check):
       
   374         model_name = capfirst(self.instance._meta.verbose_name)
       
   375 
       
   376         # A unique field
       
   377         if len(unique_check) == 1:
       
   378             field_name = unique_check[0]
       
   379             field_label = self.fields[field_name].label
       
   380             # Insert the error into the error dict, very sneaky
       
   381             return _(u"%(model_name)s with this %(field_label)s already exists.") %  {
       
   382                 'model_name': unicode(model_name),
       
   383                 'field_label': unicode(field_label)
       
   384             }
       
   385         # unique_together
       
   386         else:
       
   387             field_labels = [self.fields[field_name].label for field_name in unique_check]
       
   388             field_labels = get_text_list(field_labels, _('and'))
       
   389             return _(u"%(model_name)s with this %(field_label)s already exists.") %  {
       
   390                 'model_name': unicode(model_name),
       
   391                 'field_label': unicode(field_labels)
       
   392             }
       
   393 
       
   394     def save(self, commit=True):
       
   395         """
       
   396         Saves this ``form``'s cleaned_data into model instance
       
   397         ``self.instance``.
       
   398 
       
   399         If commit=True, then the changes to ``instance`` will be saved to the
       
   400         database. Returns ``instance``.
       
   401         """
       
   402         if self.instance.pk is None:
       
   403             fail_message = 'created'
       
   404         else:
       
   405             fail_message = 'changed'
       
   406         return save_instance(self, self.instance, self._meta.fields,
       
   407                              fail_message, commit, exclude=self._meta.exclude)
       
   408 
       
   409     save.alters_data = True
       
   410 
       
   411 class ModelForm(BaseModelForm):
       
   412     __metaclass__ = ModelFormMetaclass
       
   413 
       
   414 def modelform_factory(model, form=ModelForm, fields=None, exclude=None,
       
   415                        formfield_callback=lambda f: f.formfield()):
       
   416     # Create the inner Meta class. FIXME: ideally, we should be able to
       
   417     # construct a ModelForm without creating and passing in a temporary
       
   418     # inner class.
       
   419 
       
   420     # Build up a list of attributes that the Meta object will have.
       
   421     attrs = {'model': model}
       
   422     if fields is not None:
       
   423         attrs['fields'] = fields
       
   424     if exclude is not None:
       
   425         attrs['exclude'] = exclude
       
   426 
       
   427     # If parent form class already has an inner Meta, the Meta we're
       
   428     # creating needs to inherit from the parent's inner meta.
       
   429     parent = (object,)
       
   430     if hasattr(form, 'Meta'):
       
   431         parent = (form.Meta, object)
       
   432     Meta = type('Meta', parent, attrs)
       
   433 
       
   434     # Give this new form class a reasonable name.
       
   435     class_name = model.__name__ + 'Form'
       
   436 
       
   437     # Class attributes for the new form class.
       
   438     form_class_attrs = {
       
   439         'Meta': Meta,
       
   440         'formfield_callback': formfield_callback
       
   441     }
       
   442 
       
   443     return ModelFormMetaclass(class_name, (form,), form_class_attrs)
       
   444 
       
   445 
       
   446 # ModelFormSets ##############################################################
       
   447 
       
   448 class BaseModelFormSet(BaseFormSet):
       
   449     """
       
   450     A ``FormSet`` for editing a queryset and/or adding new objects to it.
       
   451     """
       
   452     model = None
       
   453 
       
   454     def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
       
   455                  queryset=None, **kwargs):
       
   456         self.queryset = queryset
       
   457         defaults = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix}
       
   458         defaults.update(kwargs)
       
   459         super(BaseModelFormSet, self).__init__(**defaults)
       
   460 
       
   461     def initial_form_count(self):
       
   462         """Returns the number of forms that are required in this FormSet."""
       
   463         if not (self.data or self.files):
       
   464             return len(self.get_queryset())
       
   465         return super(BaseModelFormSet, self).initial_form_count()
       
   466 
       
   467     def _existing_object(self, pk):
       
   468         if not hasattr(self, '_object_dict'):
       
   469             self._object_dict = dict([(o.pk, o) for o in self.get_queryset()])
       
   470         return self._object_dict.get(pk)
       
   471 
       
   472     def _construct_form(self, i, **kwargs):
       
   473         if self.is_bound and i < self.initial_form_count():
       
   474             pk_key = "%s-%s" % (self.add_prefix(i), self.model._meta.pk.name)
       
   475             pk = self.data[pk_key]
       
   476             pk_field = self.model._meta.pk
       
   477             pk = pk_field.get_db_prep_lookup('exact', pk)
       
   478             if isinstance(pk, list):
       
   479                 pk = pk[0]
       
   480             kwargs['instance'] = self._existing_object(pk)
       
   481         if i < self.initial_form_count() and not kwargs.get('instance'):
       
   482             kwargs['instance'] = self.get_queryset()[i]
       
   483         return super(BaseModelFormSet, self)._construct_form(i, **kwargs)
       
   484 
       
   485     def get_queryset(self):
       
   486         if not hasattr(self, '_queryset'):
       
   487             if self.queryset is not None:
       
   488                 qs = self.queryset
       
   489             else:
       
   490                 qs = self.model._default_manager.get_query_set()
       
   491 
       
   492             # If the queryset isn't already ordered we need to add an
       
   493             # artificial ordering here to make sure that all formsets
       
   494             # constructed from this queryset have the same form order.
       
   495             if not qs.ordered:
       
   496                 qs = qs.order_by(self.model._meta.pk.name)
       
   497 
       
   498             if self.max_num > 0:
       
   499                 self._queryset = qs[:self.max_num]
       
   500             else:
       
   501                 self._queryset = qs
       
   502         return self._queryset
       
   503 
       
   504     def save_new(self, form, commit=True):
       
   505         """Saves and returns a new model instance for the given form."""
       
   506         return form.save(commit=commit)
       
   507 
       
   508     def save_existing(self, form, instance, commit=True):
       
   509         """Saves and returns an existing model instance for the given form."""
       
   510         return form.save(commit=commit)
       
   511 
       
   512     def save(self, commit=True):
       
   513         """Saves model instances for every form, adding and changing instances
       
   514         as necessary, and returns the list of instances.
       
   515         """
       
   516         if not commit:
       
   517             self.saved_forms = []
       
   518             def save_m2m():
       
   519                 for form in self.saved_forms:
       
   520                     form.save_m2m()
       
   521             self.save_m2m = save_m2m
       
   522         return self.save_existing_objects(commit) + self.save_new_objects(commit)
       
   523 
       
   524     def clean(self):
       
   525         self.validate_unique()
       
   526 
       
   527     def validate_unique(self):
       
   528         # Iterate over the forms so that we can find one with potentially valid
       
   529         # data from which to extract the error checks
       
   530         for form in self.forms:
       
   531             if hasattr(form, 'cleaned_data'):
       
   532                 break
       
   533         else:
       
   534             return
       
   535         unique_checks, date_checks = form._get_unique_checks()
       
   536         errors = []
       
   537         # Do each of the unique checks (unique and unique_together)
       
   538         for unique_check in unique_checks:
       
   539             seen_data = set()
       
   540             for form in self.forms:
       
   541                 # if the form doesn't have cleaned_data then we ignore it,
       
   542                 # it's already invalid
       
   543                 if not hasattr(form, "cleaned_data"):
       
   544                     continue
       
   545                 # get each of the fields for which we have data on this form
       
   546                 if [f for f in unique_check if f in form.cleaned_data and form.cleaned_data[f] is not None]:
       
   547                     # get the data itself
       
   548                     row_data = tuple([form.cleaned_data[field] for field in unique_check])
       
   549                     # if we've aready seen it then we have a uniqueness failure
       
   550                     if row_data in seen_data:
       
   551                         # poke error messages into the right places and mark
       
   552                         # the form as invalid
       
   553                         errors.append(self.get_unique_error_message(unique_check))
       
   554                         form._errors[NON_FIELD_ERRORS] = self.get_form_error()
       
   555                         del form.cleaned_data
       
   556                         break
       
   557                     # mark the data as seen
       
   558                     seen_data.add(row_data)
       
   559         # iterate over each of the date checks now
       
   560         for date_check in date_checks:
       
   561             seen_data = set()
       
   562             lookup, field, unique_for = date_check
       
   563             for form in self.forms:
       
   564                 # if the form doesn't have cleaned_data then we ignore it,
       
   565                 # it's already invalid
       
   566                 if not hasattr(self, 'cleaned_data'):
       
   567                     continue
       
   568                 # see if we have data for both fields
       
   569                 if (form.cleaned_data and form.cleaned_data[field] is not None
       
   570                     and form.cleaned_data[unique_for] is not None):
       
   571                     # if it's a date lookup we need to get the data for all the fields
       
   572                     if lookup == 'date':
       
   573                         date = form.cleaned_data[unique_for]
       
   574                         date_data = (date.year, date.month, date.day)
       
   575                     # otherwise it's just the attribute on the date/datetime
       
   576                     # object
       
   577                     else:
       
   578                         date_data = (getattr(form.cleaned_data[unique_for], lookup),)
       
   579                     data = (form.cleaned_data[field],) + date_data
       
   580                     # if we've aready seen it then we have a uniqueness failure
       
   581                     if data in seen_data:
       
   582                         # poke error messages into the right places and mark
       
   583                         # the form as invalid
       
   584                         errors.append(self.get_date_error_message(date_check))
       
   585                         form._errors[NON_FIELD_ERRORS] = self.get_form_error()
       
   586                         del form.cleaned_data
       
   587                         break
       
   588                     seen_data.add(data)
       
   589         if errors:
       
   590             raise ValidationError(errors)
       
   591 
       
   592     def get_unique_error_message(self, unique_check):
       
   593         if len(unique_check) == 1:
       
   594             return ugettext("Please correct the duplicate data for %(field)s.") % {
       
   595                 "field": unique_check[0],
       
   596             }
       
   597         else:
       
   598             return ugettext("Please correct the duplicate data for %(field)s, "
       
   599                 "which must be unique.") % {
       
   600                     "field": get_text_list(unique_check, unicode(_("and"))),
       
   601                 }
       
   602 
       
   603     def get_date_error_message(self, date_check):
       
   604         return ugettext("Please correct the duplicate data for %(field_name)s "
       
   605             "which must be unique for the %(lookup)s in %(date_field)s.") % {
       
   606             'field_name': date_check[1],
       
   607             'date_field': date_check[2],
       
   608             'lookup': unicode(date_check[0]),
       
   609         }
       
   610 
       
   611     def get_form_error(self):
       
   612         return ugettext("Please correct the duplicate values below.")
       
   613 
       
   614     def save_existing_objects(self, commit=True):
       
   615         self.changed_objects = []
       
   616         self.deleted_objects = []
       
   617         if not self.get_queryset():
       
   618             return []
       
   619 
       
   620         saved_instances = []
       
   621         for form in self.initial_forms:
       
   622             pk_name = self._pk_field.name
       
   623             raw_pk_value = form._raw_value(pk_name)
       
   624 
       
   625             # clean() for different types of PK fields can sometimes return
       
   626             # the model instance, and sometimes the PK. Handle either.
       
   627             pk_value = form.fields[pk_name].clean(raw_pk_value)
       
   628             pk_value = getattr(pk_value, 'pk', pk_value)
       
   629 
       
   630             obj = self._existing_object(pk_value)
       
   631             if self.can_delete:
       
   632                 raw_delete_value = form._raw_value(DELETION_FIELD_NAME)
       
   633                 should_delete = form.fields[DELETION_FIELD_NAME].clean(raw_delete_value)
       
   634                 if should_delete:
       
   635                     self.deleted_objects.append(obj)
       
   636                     obj.delete()
       
   637                     continue
       
   638             if form.has_changed():
       
   639                 self.changed_objects.append((obj, form.changed_data))
       
   640                 saved_instances.append(self.save_existing(form, obj, commit=commit))
       
   641                 if not commit:
       
   642                     self.saved_forms.append(form)
       
   643         return saved_instances
       
   644 
       
   645     def save_new_objects(self, commit=True):
       
   646         self.new_objects = []
       
   647         for form in self.extra_forms:
       
   648             if not form.has_changed():
       
   649                 continue
       
   650             # If someone has marked an add form for deletion, don't save the
       
   651             # object.
       
   652             if self.can_delete:
       
   653                 raw_delete_value = form._raw_value(DELETION_FIELD_NAME)
       
   654                 should_delete = form.fields[DELETION_FIELD_NAME].clean(raw_delete_value)
       
   655                 if should_delete:
       
   656                     continue
       
   657             self.new_objects.append(self.save_new(form, commit=commit))
       
   658             if not commit:
       
   659                 self.saved_forms.append(form)
       
   660         return self.new_objects
       
   661 
       
   662     def add_fields(self, form, index):
       
   663         """Add a hidden field for the object's primary key."""
       
   664         from django.db.models import AutoField, OneToOneField, ForeignKey
       
   665         self._pk_field = pk = self.model._meta.pk
       
   666         # If a pk isn't editable, then it won't be on the form, so we need to
       
   667         # add it here so we can tell which object is which when we get the
       
   668         # data back. Generally, pk.editable should be false, but for some
       
   669         # reason, auto_created pk fields and AutoField's editable attribute is
       
   670         # True, so check for that as well.
       
   671         def pk_is_not_editable(pk):
       
   672             return ((not pk.editable) or (pk.auto_created or isinstance(pk, AutoField))
       
   673                 or (pk.rel and pk.rel.parent_link and pk_is_not_editable(pk.rel.to._meta.pk)))
       
   674         if pk_is_not_editable(pk) or pk.name not in form.fields:
       
   675             if form.is_bound:
       
   676                 pk_value = form.instance.pk
       
   677             else:
       
   678                 try:
       
   679                     pk_value = self.get_queryset()[index].pk
       
   680                 except IndexError:
       
   681                     pk_value = None
       
   682             if isinstance(pk, OneToOneField) or isinstance(pk, ForeignKey):
       
   683                 qs = pk.rel.to._default_manager.get_query_set()
       
   684             else:
       
   685                 qs = self.model._default_manager.get_query_set()
       
   686             form.fields[self._pk_field.name] = ModelChoiceField(qs, initial=pk_value, required=False, widget=HiddenInput)
       
   687         super(BaseModelFormSet, self).add_fields(form, index)
       
   688 
       
   689 def modelformset_factory(model, form=ModelForm, formfield_callback=lambda f: f.formfield(),
       
   690                          formset=BaseModelFormSet,
       
   691                          extra=1, can_delete=False, can_order=False,
       
   692                          max_num=0, fields=None, exclude=None):
       
   693     """
       
   694     Returns a FormSet class for the given Django model class.
       
   695     """
       
   696     form = modelform_factory(model, form=form, fields=fields, exclude=exclude,
       
   697                              formfield_callback=formfield_callback)
       
   698     FormSet = formset_factory(form, formset, extra=extra, max_num=max_num,
       
   699                               can_order=can_order, can_delete=can_delete)
       
   700     FormSet.model = model
       
   701     return FormSet
       
   702 
       
   703 
       
   704 # InlineFormSets #############################################################
       
   705 
       
   706 class BaseInlineFormSet(BaseModelFormSet):
       
   707     """A formset for child objects related to a parent."""
       
   708     def __init__(self, data=None, files=None, instance=None,
       
   709                  save_as_new=False, prefix=None):
       
   710         from django.db.models.fields.related import RelatedObject
       
   711         if instance is None:
       
   712             self.instance = self.model()
       
   713         else:
       
   714             self.instance = instance
       
   715         self.save_as_new = save_as_new
       
   716         # is there a better way to get the object descriptor?
       
   717         self.rel_name = RelatedObject(self.fk.rel.to, self.model, self.fk).get_accessor_name()
       
   718         if self.fk.rel.field_name == self.fk.rel.to._meta.pk.name:
       
   719             backlink_value = self.instance
       
   720         else:
       
   721             backlink_value = getattr(self.instance, self.fk.rel.field_name)
       
   722         qs = self.model._default_manager.filter(**{self.fk.name: backlink_value})
       
   723         super(BaseInlineFormSet, self).__init__(data, files, prefix=prefix,
       
   724                                                 queryset=qs)
       
   725 
       
   726     def initial_form_count(self):
       
   727         if self.save_as_new:
       
   728             return 0
       
   729         return super(BaseInlineFormSet, self).initial_form_count()
       
   730 
       
   731     def total_form_count(self):
       
   732         if self.save_as_new:
       
   733             return super(BaseInlineFormSet, self).initial_form_count()
       
   734         return super(BaseInlineFormSet, self).total_form_count()
       
   735 
       
   736     def _construct_form(self, i, **kwargs):
       
   737         form = super(BaseInlineFormSet, self)._construct_form(i, **kwargs)
       
   738         if self.save_as_new:
       
   739             # Remove the primary key from the form's data, we are only
       
   740             # creating new instances
       
   741             form.data[form.add_prefix(self._pk_field.name)] = None
       
   742 
       
   743             # Remove the foreign key from the form's data
       
   744             form.data[form.add_prefix(self.fk.name)] = None
       
   745         return form
       
   746 
       
   747     #@classmethod
       
   748     def get_default_prefix(cls):
       
   749         from django.db.models.fields.related import RelatedObject
       
   750         return RelatedObject(cls.fk.rel.to, cls.model, cls.fk).get_accessor_name()
       
   751     get_default_prefix = classmethod(get_default_prefix)
       
   752 
       
   753     def save_new(self, form, commit=True):
       
   754         # Use commit=False so we can assign the parent key afterwards, then
       
   755         # save the object.
       
   756         obj = form.save(commit=False)
       
   757         pk_value = getattr(self.instance, self.fk.rel.field_name)
       
   758         setattr(obj, self.fk.get_attname(), getattr(pk_value, 'pk', pk_value))
       
   759         if commit:
       
   760             obj.save()
       
   761         # form.save_m2m() can be called via the formset later on if commit=False
       
   762         if commit and hasattr(form, 'save_m2m'):
       
   763             form.save_m2m()
       
   764         return obj
       
   765 
       
   766     def add_fields(self, form, index):
       
   767         super(BaseInlineFormSet, self).add_fields(form, index)
       
   768         if self._pk_field == self.fk:
       
   769             form.fields[self._pk_field.name] = InlineForeignKeyField(self.instance, pk_field=True)
       
   770         else:
       
   771             # The foreign key field might not be on the form, so we poke at the
       
   772             # Model field to get the label, since we need that for error messages.
       
   773             kwargs = {
       
   774                 'label': getattr(form.fields.get(self.fk.name), 'label', capfirst(self.fk.verbose_name))
       
   775             }
       
   776             if self.fk.rel.field_name != self.fk.rel.to._meta.pk.name:
       
   777                 kwargs['to_field'] = self.fk.rel.field_name
       
   778             form.fields[self.fk.name] = InlineForeignKeyField(self.instance, **kwargs)
       
   779 
       
   780     def get_unique_error_message(self, unique_check):
       
   781         unique_check = [field for field in unique_check if field != self.fk.name]
       
   782         return super(BaseInlineFormSet, self).get_unique_error_message(unique_check)
       
   783 
       
   784 def _get_foreign_key(parent_model, model, fk_name=None, can_fail=False):
       
   785     """
       
   786     Finds and returns the ForeignKey from model to parent if there is one
       
   787     (returns None if can_fail is True and no such field exists). If fk_name is
       
   788     provided, assume it is the name of the ForeignKey field. Unles can_fail is
       
   789     True, an exception is raised if there is no ForeignKey from model to
       
   790     parent_model.
       
   791     """
       
   792     # avoid circular import
       
   793     from django.db.models import ForeignKey
       
   794     opts = model._meta
       
   795     if fk_name:
       
   796         fks_to_parent = [f for f in opts.fields if f.name == fk_name]
       
   797         if len(fks_to_parent) == 1:
       
   798             fk = fks_to_parent[0]
       
   799             if not isinstance(fk, ForeignKey) or \
       
   800                     (fk.rel.to != parent_model and
       
   801                      fk.rel.to not in parent_model._meta.get_parent_list()):
       
   802                 raise Exception("fk_name '%s' is not a ForeignKey to %s" % (fk_name, parent_model))
       
   803         elif len(fks_to_parent) == 0:
       
   804             raise Exception("%s has no field named '%s'" % (model, fk_name))
       
   805     else:
       
   806         # Try to discover what the ForeignKey from model to parent_model is
       
   807         fks_to_parent = [
       
   808             f for f in opts.fields
       
   809             if isinstance(f, ForeignKey)
       
   810             and (f.rel.to == parent_model
       
   811                 or f.rel.to in parent_model._meta.get_parent_list())
       
   812         ]
       
   813         if len(fks_to_parent) == 1:
       
   814             fk = fks_to_parent[0]
       
   815         elif len(fks_to_parent) == 0:
       
   816             if can_fail:
       
   817                 return
       
   818             raise Exception("%s has no ForeignKey to %s" % (model, parent_model))
       
   819         else:
       
   820             raise Exception("%s has more than 1 ForeignKey to %s" % (model, parent_model))
       
   821     return fk
       
   822 
       
   823 
       
   824 def inlineformset_factory(parent_model, model, form=ModelForm,
       
   825                           formset=BaseInlineFormSet, fk_name=None,
       
   826                           fields=None, exclude=None,
       
   827                           extra=3, can_order=False, can_delete=True, max_num=0,
       
   828                           formfield_callback=lambda f: f.formfield()):
       
   829     """
       
   830     Returns an ``InlineFormSet`` for the given kwargs.
       
   831 
       
   832     You must provide ``fk_name`` if ``model`` has more than one ``ForeignKey``
       
   833     to ``parent_model``.
       
   834     """
       
   835     fk = _get_foreign_key(parent_model, model, fk_name=fk_name)
       
   836     # enforce a max_num=1 when the foreign key to the parent model is unique.
       
   837     if fk.unique:
       
   838         max_num = 1
       
   839     kwargs = {
       
   840         'form': form,
       
   841         'formfield_callback': formfield_callback,
       
   842         'formset': formset,
       
   843         'extra': extra,
       
   844         'can_delete': can_delete,
       
   845         'can_order': can_order,
       
   846         'fields': fields,
       
   847         'exclude': exclude,
       
   848         'max_num': max_num,
       
   849     }
       
   850     FormSet = modelformset_factory(model, **kwargs)
       
   851     FormSet.fk = fk
       
   852     return FormSet
       
   853 
       
   854 
       
   855 # Fields #####################################################################
       
   856 
       
   857 class InlineForeignKeyHiddenInput(HiddenInput):
       
   858     def _has_changed(self, initial, data):
       
   859         return False
       
   860 
       
   861 class InlineForeignKeyField(Field):
       
   862     """
       
   863     A basic integer field that deals with validating the given value to a
       
   864     given parent instance in an inline.
       
   865     """
       
   866     default_error_messages = {
       
   867         'invalid_choice': _(u'The inline foreign key did not match the parent instance primary key.'),
       
   868     }
       
   869 
       
   870     def __init__(self, parent_instance, *args, **kwargs):
       
   871         self.parent_instance = parent_instance
       
   872         self.pk_field = kwargs.pop("pk_field", False)
       
   873         self.to_field = kwargs.pop("to_field", None)
       
   874         if self.parent_instance is not None:
       
   875             if self.to_field:
       
   876                 kwargs["initial"] = getattr(self.parent_instance, self.to_field)
       
   877             else:
       
   878                 kwargs["initial"] = self.parent_instance.pk
       
   879         kwargs["required"] = False
       
   880         kwargs["widget"] = InlineForeignKeyHiddenInput
       
   881         super(InlineForeignKeyField, self).__init__(*args, **kwargs)
       
   882 
       
   883     def clean(self, value):
       
   884         if value in EMPTY_VALUES:
       
   885             if self.pk_field:
       
   886                 return None
       
   887             # if there is no value act as we did before.
       
   888             return self.parent_instance
       
   889         # ensure the we compare the values as equal types.
       
   890         if self.to_field:
       
   891             orig = getattr(self.parent_instance, self.to_field)
       
   892         else:
       
   893             orig = self.parent_instance.pk
       
   894         if force_unicode(value) != force_unicode(orig):
       
   895             raise ValidationError(self.error_messages['invalid_choice'])
       
   896         return self.parent_instance
       
   897 
       
   898 class ModelChoiceIterator(object):
       
   899     def __init__(self, field):
       
   900         self.field = field
       
   901         self.queryset = field.queryset
       
   902 
       
   903     def __iter__(self):
       
   904         if self.field.empty_label is not None:
       
   905             yield (u"", self.field.empty_label)
       
   906         if self.field.cache_choices:
       
   907             if self.field.choice_cache is None:
       
   908                 self.field.choice_cache = [
       
   909                     self.choice(obj) for obj in self.queryset.all()
       
   910                 ]
       
   911             for choice in self.field.choice_cache:
       
   912                 yield choice
       
   913         else:
       
   914             for obj in self.queryset.all():
       
   915                 yield self.choice(obj)
       
   916 
       
   917     def choice(self, obj):
       
   918         if self.field.to_field_name:
       
   919             key = obj.serializable_value(self.field.to_field_name)
       
   920         else:
       
   921             key = obj.pk
       
   922         return (key, self.field.label_from_instance(obj))
       
   923 
       
   924 
       
   925 class ModelChoiceField(ChoiceField):
       
   926     """A ChoiceField whose choices are a model QuerySet."""
       
   927     # This class is a subclass of ChoiceField for purity, but it doesn't
       
   928     # actually use any of ChoiceField's implementation.
       
   929     default_error_messages = {
       
   930         'invalid_choice': _(u'Select a valid choice. That choice is not one of'
       
   931                             u' the available choices.'),
       
   932     }
       
   933 
       
   934     def __init__(self, queryset, empty_label=u"---------", cache_choices=False,
       
   935                  required=True, widget=None, label=None, initial=None,
       
   936                  help_text=None, to_field_name=None, *args, **kwargs):
       
   937         if required and (initial is not None):
       
   938             self.empty_label = None
       
   939         else:
       
   940             self.empty_label = empty_label
       
   941         self.cache_choices = cache_choices
       
   942 
       
   943         # Call Field instead of ChoiceField __init__() because we don't need
       
   944         # ChoiceField.__init__().
       
   945         Field.__init__(self, required, widget, label, initial, help_text,
       
   946                        *args, **kwargs)
       
   947         self.queryset = queryset
       
   948         self.choice_cache = None
       
   949         self.to_field_name = to_field_name
       
   950 
       
   951     def _get_queryset(self):
       
   952         return self._queryset
       
   953 
       
   954     def _set_queryset(self, queryset):
       
   955         self._queryset = queryset
       
   956         self.widget.choices = self.choices
       
   957 
       
   958     queryset = property(_get_queryset, _set_queryset)
       
   959 
       
   960     # this method will be used to create object labels by the QuerySetIterator.
       
   961     # Override it to customize the label.
       
   962     def label_from_instance(self, obj):
       
   963         """
       
   964         This method is used to convert objects into strings; it's used to
       
   965         generate the labels for the choices presented by this object. Subclasses
       
   966         can override this method to customize the display of the choices.
       
   967         """
       
   968         return smart_unicode(obj)
       
   969 
       
   970     def _get_choices(self):
       
   971         # If self._choices is set, then somebody must have manually set
       
   972         # the property self.choices. In this case, just return self._choices.
       
   973         if hasattr(self, '_choices'):
       
   974             return self._choices
       
   975 
       
   976         # Otherwise, execute the QuerySet in self.queryset to determine the
       
   977         # choices dynamically. Return a fresh QuerySetIterator that has not been
       
   978         # consumed. Note that we're instantiating a new QuerySetIterator *each*
       
   979         # time _get_choices() is called (and, thus, each time self.choices is
       
   980         # accessed) so that we can ensure the QuerySet has not been consumed. This
       
   981         # construct might look complicated but it allows for lazy evaluation of
       
   982         # the queryset.
       
   983         return ModelChoiceIterator(self)
       
   984 
       
   985     choices = property(_get_choices, ChoiceField._set_choices)
       
   986 
       
   987     def clean(self, value):
       
   988         Field.clean(self, value)
       
   989         if value in EMPTY_VALUES:
       
   990             return None
       
   991         try:
       
   992             key = self.to_field_name or 'pk'
       
   993             value = self.queryset.get(**{key: value})
       
   994         except self.queryset.model.DoesNotExist:
       
   995             raise ValidationError(self.error_messages['invalid_choice'])
       
   996         return value
       
   997 
       
   998 class ModelMultipleChoiceField(ModelChoiceField):
       
   999     """A MultipleChoiceField whose choices are a model QuerySet."""
       
  1000     widget = SelectMultiple
       
  1001     hidden_widget = MultipleHiddenInput
       
  1002     default_error_messages = {
       
  1003         'list': _(u'Enter a list of values.'),
       
  1004         'invalid_choice': _(u'Select a valid choice. %s is not one of the'
       
  1005                             u' available choices.'),
       
  1006         'invalid_pk_value': _(u'"%s" is not a valid value for a primary key.')
       
  1007     }
       
  1008 
       
  1009     def __init__(self, queryset, cache_choices=False, required=True,
       
  1010                  widget=None, label=None, initial=None,
       
  1011                  help_text=None, *args, **kwargs):
       
  1012         super(ModelMultipleChoiceField, self).__init__(queryset, None,
       
  1013             cache_choices, required, widget, label, initial, help_text,
       
  1014             *args, **kwargs)
       
  1015 
       
  1016     def clean(self, value):
       
  1017         if self.required and not value:
       
  1018             raise ValidationError(self.error_messages['required'])
       
  1019         elif not self.required and not value:
       
  1020             return []
       
  1021         if not isinstance(value, (list, tuple)):
       
  1022             raise ValidationError(self.error_messages['list'])
       
  1023         for pk in value:
       
  1024             try:
       
  1025                 self.queryset.filter(pk=pk)
       
  1026             except ValueError:
       
  1027                 raise ValidationError(self.error_messages['invalid_pk_value'] % pk)
       
  1028         qs = self.queryset.filter(pk__in=value)
       
  1029         pks = set([force_unicode(o.pk) for o in qs])
       
  1030         for val in value:
       
  1031             if force_unicode(val) not in pks:
       
  1032                 raise ValidationError(self.error_messages['invalid_choice'] % val)
       
  1033         return qs