app/django/db/models/fields/related.py
changeset 54 03e267d67478
child 323 ff1a9aa48cfd
equal deleted inserted replaced
53:57b4279d8c4e 54:03e267d67478
       
     1 from django.db import connection, transaction
       
     2 from django.db.models import signals, get_model
       
     3 from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, get_ul_class, FieldDoesNotExist
       
     4 from django.db.models.related import RelatedObject
       
     5 from django.db.models.query_utils import QueryWrapper
       
     6 from django.utils.text import capfirst
       
     7 from django.utils.translation import ugettext_lazy, string_concat, ungettext, ugettext as _
       
     8 from django.utils.functional import curry
       
     9 from django.utils.encoding import smart_unicode
       
    10 from django.core import validators
       
    11 from django import oldforms
       
    12 from django import newforms as forms
       
    13 from django.dispatch import dispatcher
       
    14 
       
    15 try:
       
    16     set
       
    17 except NameError:
       
    18     from sets import Set as set   # Python 2.3 fallback
       
    19 
       
    20 # Values for Relation.edit_inline.
       
    21 TABULAR, STACKED = 1, 2
       
    22 
       
    23 RECURSIVE_RELATIONSHIP_CONSTANT = 'self'
       
    24 
       
    25 pending_lookups = {}
       
    26 
       
    27 def add_lazy_relation(cls, field, relation):
       
    28     """
       
    29     Adds a lookup on ``cls`` when a related field is defined using a string,
       
    30     i.e.::
       
    31 
       
    32         class MyModel(Model):
       
    33             fk = ForeignKey("AnotherModel")
       
    34 
       
    35     This string can be:
       
    36 
       
    37         * RECURSIVE_RELATIONSHIP_CONSTANT (i.e. "self") to indicate a recursive
       
    38           relation.
       
    39 
       
    40         * The name of a model (i.e "AnotherModel") to indicate another model in
       
    41           the same app.
       
    42 
       
    43         * An app-label and model name (i.e. "someapp.AnotherModel") to indicate
       
    44           another model in a different app.
       
    45 
       
    46     If the other model hasn't yet been loaded -- almost a given if you're using
       
    47     lazy relationships -- then the relation won't be set up until the
       
    48     class_prepared signal fires at the end of model initialization.
       
    49     """
       
    50     # Check for recursive relations
       
    51     if relation == RECURSIVE_RELATIONSHIP_CONSTANT:
       
    52         app_label = cls._meta.app_label
       
    53         model_name = cls.__name__
       
    54 
       
    55     else:
       
    56         # Look for an "app.Model" relation
       
    57         try:
       
    58             app_label, model_name = relation.split(".")
       
    59         except ValueError:
       
    60             # If we can't split, assume a model in current app
       
    61             app_label = cls._meta.app_label
       
    62             model_name = relation
       
    63 
       
    64     # Try to look up the related model, and if it's already loaded resolve the
       
    65     # string right away. If get_model returns None, it means that the related
       
    66     # model isn't loaded yet, so we need to pend the relation until the class
       
    67     # is prepared.
       
    68     model = get_model(app_label, model_name, False)
       
    69     if model:
       
    70         field.rel.to = model
       
    71         field.do_related_class(model, cls)
       
    72     else:
       
    73         key = (app_label, model_name)
       
    74         value = (cls, field)
       
    75         pending_lookups.setdefault(key, []).append(value)
       
    76 
       
    77 def do_pending_lookups(sender):
       
    78     """
       
    79     Handle any pending relations to the sending model. Sent from class_prepared.
       
    80     """
       
    81     key = (sender._meta.app_label, sender.__name__)
       
    82     for cls, field in pending_lookups.pop(key, []):
       
    83         field.rel.to = sender
       
    84         field.do_related_class(sender, cls)
       
    85 
       
    86 dispatcher.connect(do_pending_lookups, signal=signals.class_prepared)
       
    87 
       
    88 def manipulator_valid_rel_key(f, self, field_data, all_data):
       
    89     "Validates that the value is a valid foreign key"
       
    90     klass = f.rel.to
       
    91     try:
       
    92         klass._default_manager.get(**{f.rel.field_name: field_data})
       
    93     except klass.DoesNotExist:
       
    94         raise validators.ValidationError, _("Please enter a valid %s.") % f.verbose_name
       
    95 
       
    96 #HACK
       
    97 class RelatedField(object):
       
    98     def contribute_to_class(self, cls, name):
       
    99         sup = super(RelatedField, self)
       
   100 
       
   101         # Add an accessor to allow easy determination of the related query path for this field
       
   102         self.related_query_name = curry(self._get_related_query_name, cls._meta)
       
   103 
       
   104         if hasattr(sup, 'contribute_to_class'):
       
   105             sup.contribute_to_class(cls, name)
       
   106         other = self.rel.to
       
   107         if isinstance(other, basestring):
       
   108             add_lazy_relation(cls, self, other)
       
   109         else:
       
   110             self.do_related_class(other, cls)
       
   111         if not cls._meta.abstract and self.rel.related_name:
       
   112             self.rel.related_name = self.rel.related_name % {'class': cls.__name__.lower()}
       
   113 
       
   114     def set_attributes_from_rel(self):
       
   115         self.name = self.name or (self.rel.to._meta.object_name.lower() + '_' + self.rel.to._meta.pk.name)
       
   116         self.verbose_name = self.verbose_name or self.rel.to._meta.verbose_name
       
   117         self.rel.field_name = self.rel.field_name or self.rel.to._meta.pk.name
       
   118 
       
   119     def do_related_class(self, other, cls):
       
   120         self.set_attributes_from_rel()
       
   121         related = RelatedObject(other, cls, self)
       
   122         self.contribute_to_related_class(other, related)
       
   123 
       
   124     def get_db_prep_lookup(self, lookup_type, value):
       
   125         # If we are doing a lookup on a Related Field, we must be
       
   126         # comparing object instances. The value should be the PK of value,
       
   127         # not value itself.
       
   128         def pk_trace(value):
       
   129             # Value may be a primary key, or an object held in a relation.
       
   130             # If it is an object, then we need to get the primary key value for
       
   131             # that object. In certain conditions (especially one-to-one relations),
       
   132             # the primary key may itself be an object - so we need to keep drilling
       
   133             # down until we hit a value that can be used for a comparison.
       
   134             v = value
       
   135             try:
       
   136                 while True:
       
   137                     v = getattr(v, v._meta.pk.name)
       
   138             except AttributeError:
       
   139                 pass
       
   140             return v
       
   141 
       
   142         if hasattr(value, 'as_sql'):
       
   143             sql, params = value.as_sql()
       
   144             return QueryWrapper(('(%s)' % sql), params)
       
   145         if lookup_type == 'exact':
       
   146             return [pk_trace(value)]
       
   147         if lookup_type == 'in':
       
   148             return [pk_trace(v) for v in value]
       
   149         elif lookup_type == 'isnull':
       
   150             return []
       
   151         raise TypeError, "Related Field has invalid lookup: %s" % lookup_type
       
   152 
       
   153     def _get_related_query_name(self, opts):
       
   154         # This method defines the name that can be used to identify this
       
   155         # related object in a table-spanning query. It uses the lower-cased
       
   156         # object_name by default, but this can be overridden with the
       
   157         # "related_name" option.
       
   158         return self.rel.related_name or opts.object_name.lower()
       
   159 
       
   160 class SingleRelatedObjectDescriptor(object):
       
   161     # This class provides the functionality that makes the related-object
       
   162     # managers available as attributes on a model class, for fields that have
       
   163     # a single "remote" value, on the class pointed to by a related field.
       
   164     # In the example "place.restaurant", the restaurant attribute is a
       
   165     # SingleRelatedObjectDescriptor instance.
       
   166     def __init__(self, related):
       
   167         self.related = related
       
   168         self.cache_name = '_%s_cache' % related.get_accessor_name()
       
   169 
       
   170     def __get__(self, instance, instance_type=None):
       
   171         if instance is None:
       
   172             raise AttributeError, "%s must be accessed via instance" % self.related.opts.object_name
       
   173 
       
   174         try:
       
   175             return getattr(instance, self.cache_name)
       
   176         except AttributeError:
       
   177             params = {'%s__pk' % self.related.field.name: instance._get_pk_val()}
       
   178             rel_obj = self.related.model._default_manager.get(**params)
       
   179             setattr(instance, self.cache_name, rel_obj)
       
   180             return rel_obj
       
   181 
       
   182     def __set__(self, instance, value):
       
   183         if instance is None:
       
   184             raise AttributeError, "%s must be accessed via instance" % self.related.opts.object_name
       
   185         # Set the value of the related field
       
   186         setattr(value, self.related.field.rel.get_related_field().attname, instance)
       
   187 
       
   188         # Clear the cache, if it exists
       
   189         try:
       
   190             delattr(value, self.related.field.get_cache_name())
       
   191         except AttributeError:
       
   192             pass
       
   193 
       
   194 class ReverseSingleRelatedObjectDescriptor(object):
       
   195     # This class provides the functionality that makes the related-object
       
   196     # managers available as attributes on a model class, for fields that have
       
   197     # a single "remote" value, on the class that defines the related field.
       
   198     # In the example "choice.poll", the poll attribute is a
       
   199     # ReverseSingleRelatedObjectDescriptor instance.
       
   200     def __init__(self, field_with_rel):
       
   201         self.field = field_with_rel
       
   202 
       
   203     def __get__(self, instance, instance_type=None):
       
   204         if instance is None:
       
   205             raise AttributeError, "%s must be accessed via instance" % self.field.name
       
   206         cache_name = self.field.get_cache_name()
       
   207         try:
       
   208             return getattr(instance, cache_name)
       
   209         except AttributeError:
       
   210             val = getattr(instance, self.field.attname)
       
   211             if val is None:
       
   212                 # If NULL is an allowed value, return it.
       
   213                 if self.field.null:
       
   214                     return None
       
   215                 raise self.field.rel.to.DoesNotExist
       
   216             other_field = self.field.rel.get_related_field()
       
   217             if other_field.rel:
       
   218                 params = {'%s__pk' % self.field.rel.field_name: val}
       
   219             else:
       
   220                 params = {'%s__exact' % self.field.rel.field_name: val}
       
   221             rel_obj = self.field.rel.to._default_manager.get(**params)
       
   222             setattr(instance, cache_name, rel_obj)
       
   223             return rel_obj
       
   224 
       
   225     def __set__(self, instance, value):
       
   226         if instance is None:
       
   227             raise AttributeError, "%s must be accessed via instance" % self._field.name
       
   228         # Set the value of the related field
       
   229         try:
       
   230             val = getattr(value, self.field.rel.get_related_field().attname)
       
   231         except AttributeError:
       
   232             val = None
       
   233         setattr(instance, self.field.attname, val)
       
   234 
       
   235         # Clear the cache, if it exists
       
   236         try:
       
   237             delattr(instance, self.field.get_cache_name())
       
   238         except AttributeError:
       
   239             pass
       
   240 
       
   241 class ForeignRelatedObjectsDescriptor(object):
       
   242     # This class provides the functionality that makes the related-object
       
   243     # managers available as attributes on a model class, for fields that have
       
   244     # multiple "remote" values and have a ForeignKey pointed at them by
       
   245     # some other model. In the example "poll.choice_set", the choice_set
       
   246     # attribute is a ForeignRelatedObjectsDescriptor instance.
       
   247     def __init__(self, related):
       
   248         self.related = related   # RelatedObject instance
       
   249 
       
   250     def __get__(self, instance, instance_type=None):
       
   251         if instance is None:
       
   252             raise AttributeError, "Manager must be accessed via instance"
       
   253 
       
   254         rel_field = self.related.field
       
   255         rel_model = self.related.model
       
   256 
       
   257         # Dynamically create a class that subclasses the related
       
   258         # model's default manager.
       
   259         superclass = self.related.model._default_manager.__class__
       
   260 
       
   261         class RelatedManager(superclass):
       
   262             def get_query_set(self):
       
   263                 return superclass.get_query_set(self).filter(**(self.core_filters))
       
   264 
       
   265             def add(self, *objs):
       
   266                 for obj in objs:
       
   267                     setattr(obj, rel_field.name, instance)
       
   268                     obj.save()
       
   269             add.alters_data = True
       
   270 
       
   271             def create(self, **kwargs):
       
   272                 new_obj = self.model(**kwargs)
       
   273                 self.add(new_obj)
       
   274                 return new_obj
       
   275             create.alters_data = True
       
   276 
       
   277             # remove() and clear() are only provided if the ForeignKey can have a value of null.
       
   278             if rel_field.null:
       
   279                 def remove(self, *objs):
       
   280                     val = getattr(instance, rel_field.rel.get_related_field().attname)
       
   281                     for obj in objs:
       
   282                         # Is obj actually part of this descriptor set?
       
   283                         if getattr(obj, rel_field.attname) == val:
       
   284                             setattr(obj, rel_field.name, None)
       
   285                             obj.save()
       
   286                         else:
       
   287                             raise rel_field.rel.to.DoesNotExist, "%r is not related to %r." % (obj, instance)
       
   288                 remove.alters_data = True
       
   289 
       
   290                 def clear(self):
       
   291                     for obj in self.all():
       
   292                         setattr(obj, rel_field.name, None)
       
   293                         obj.save()
       
   294                 clear.alters_data = True
       
   295 
       
   296         manager = RelatedManager()
       
   297         manager.core_filters = {'%s__pk' % rel_field.name: getattr(instance, rel_field.rel.get_related_field().attname)}
       
   298         manager.model = self.related.model
       
   299 
       
   300         return manager
       
   301 
       
   302     def __set__(self, instance, value):
       
   303         if instance is None:
       
   304             raise AttributeError, "Manager must be accessed via instance"
       
   305 
       
   306         manager = self.__get__(instance)
       
   307         # If the foreign key can support nulls, then completely clear the related set.
       
   308         # Otherwise, just move the named objects into the set.
       
   309         if self.related.field.null:
       
   310             manager.clear()
       
   311         manager.add(*value)
       
   312 
       
   313 def create_many_related_manager(superclass):
       
   314     """Creates a manager that subclasses 'superclass' (which is a Manager)
       
   315     and adds behavior for many-to-many related objects."""
       
   316     class ManyRelatedManager(superclass):
       
   317         def __init__(self, model=None, core_filters=None, instance=None, symmetrical=None,
       
   318                 join_table=None, source_col_name=None, target_col_name=None):
       
   319             super(ManyRelatedManager, self).__init__()
       
   320             self.core_filters = core_filters
       
   321             self.model = model
       
   322             self.symmetrical = symmetrical
       
   323             self.instance = instance
       
   324             self.join_table = join_table
       
   325             self.source_col_name = source_col_name
       
   326             self.target_col_name = target_col_name
       
   327             self._pk_val = self.instance._get_pk_val()
       
   328             if self._pk_val is None:
       
   329                 raise ValueError("%r instance needs to have a primary key value before a many-to-many relationship can be used." % model)
       
   330 
       
   331         def get_query_set(self):
       
   332             return superclass.get_query_set(self).filter(**(self.core_filters))
       
   333 
       
   334         def add(self, *objs):
       
   335             self._add_items(self.source_col_name, self.target_col_name, *objs)
       
   336 
       
   337             # If this is a symmetrical m2m relation to self, add the mirror entry in the m2m table
       
   338             if self.symmetrical:
       
   339                 self._add_items(self.target_col_name, self.source_col_name, *objs)
       
   340         add.alters_data = True
       
   341 
       
   342         def remove(self, *objs):
       
   343             self._remove_items(self.source_col_name, self.target_col_name, *objs)
       
   344 
       
   345             # If this is a symmetrical m2m relation to self, remove the mirror entry in the m2m table
       
   346             if self.symmetrical:
       
   347                 self._remove_items(self.target_col_name, self.source_col_name, *objs)
       
   348         remove.alters_data = True
       
   349 
       
   350         def clear(self):
       
   351             self._clear_items(self.source_col_name)
       
   352 
       
   353             # If this is a symmetrical m2m relation to self, clear the mirror entry in the m2m table
       
   354             if self.symmetrical:
       
   355                 self._clear_items(self.target_col_name)
       
   356         clear.alters_data = True
       
   357 
       
   358         def create(self, **kwargs):
       
   359             new_obj = self.model(**kwargs)
       
   360             new_obj.save()
       
   361             self.add(new_obj)
       
   362             return new_obj
       
   363         create.alters_data = True
       
   364 
       
   365         def _add_items(self, source_col_name, target_col_name, *objs):
       
   366             # join_table: name of the m2m link table
       
   367             # source_col_name: the PK colname in join_table for the source object
       
   368             # target_col_name: the PK colname in join_table for the target object
       
   369             # *objs - objects to add. Either object instances, or primary keys of object instances.
       
   370 
       
   371             # If there aren't any objects, there is nothing to do.
       
   372             if objs:
       
   373                 # Check that all the objects are of the right type
       
   374                 new_ids = set()
       
   375                 for obj in objs:
       
   376                     if isinstance(obj, self.model):
       
   377                         new_ids.add(obj._get_pk_val())
       
   378                     else:
       
   379                         new_ids.add(obj)
       
   380                 # Add the newly created or already existing objects to the join table.
       
   381                 # First find out which items are already added, to avoid adding them twice
       
   382                 cursor = connection.cursor()
       
   383                 cursor.execute("SELECT %s FROM %s WHERE %s = %%s AND %s IN (%s)" % \
       
   384                     (target_col_name, self.join_table, source_col_name,
       
   385                     target_col_name, ",".join(['%s'] * len(new_ids))),
       
   386                     [self._pk_val] + list(new_ids))
       
   387                 existing_ids = set([row[0] for row in cursor.fetchall()])
       
   388 
       
   389                 # Add the ones that aren't there already
       
   390                 for obj_id in (new_ids - existing_ids):
       
   391                     cursor.execute("INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \
       
   392                         (self.join_table, source_col_name, target_col_name),
       
   393                         [self._pk_val, obj_id])
       
   394                 transaction.commit_unless_managed()
       
   395 
       
   396         def _remove_items(self, source_col_name, target_col_name, *objs):
       
   397             # source_col_name: the PK colname in join_table for the source object
       
   398             # target_col_name: the PK colname in join_table for the target object
       
   399             # *objs - objects to remove
       
   400 
       
   401             # If there aren't any objects, there is nothing to do.
       
   402             if objs:
       
   403                 # Check that all the objects are of the right type
       
   404                 old_ids = set()
       
   405                 for obj in objs:
       
   406                     if isinstance(obj, self.model):
       
   407                         old_ids.add(obj._get_pk_val())
       
   408                     else:
       
   409                         old_ids.add(obj)
       
   410                 # Remove the specified objects from the join table
       
   411                 cursor = connection.cursor()
       
   412                 cursor.execute("DELETE FROM %s WHERE %s = %%s AND %s IN (%s)" % \
       
   413                     (self.join_table, source_col_name,
       
   414                     target_col_name, ",".join(['%s'] * len(old_ids))),
       
   415                     [self._pk_val] + list(old_ids))
       
   416                 transaction.commit_unless_managed()
       
   417 
       
   418         def _clear_items(self, source_col_name):
       
   419             # source_col_name: the PK colname in join_table for the source object
       
   420             cursor = connection.cursor()
       
   421             cursor.execute("DELETE FROM %s WHERE %s = %%s" % \
       
   422                 (self.join_table, source_col_name),
       
   423                 [self._pk_val])
       
   424             transaction.commit_unless_managed()
       
   425 
       
   426     return ManyRelatedManager
       
   427 
       
   428 class ManyRelatedObjectsDescriptor(object):
       
   429     # This class provides the functionality that makes the related-object
       
   430     # managers available as attributes on a model class, for fields that have
       
   431     # multiple "remote" values and have a ManyToManyField pointed at them by
       
   432     # some other model (rather than having a ManyToManyField themselves).
       
   433     # In the example "publication.article_set", the article_set attribute is a
       
   434     # ManyRelatedObjectsDescriptor instance.
       
   435     def __init__(self, related):
       
   436         self.related = related   # RelatedObject instance
       
   437 
       
   438     def __get__(self, instance, instance_type=None):
       
   439         if instance is None:
       
   440             raise AttributeError, "Manager must be accessed via instance"
       
   441 
       
   442         # Dynamically create a class that subclasses the related
       
   443         # model's default manager.
       
   444         rel_model = self.related.model
       
   445         superclass = rel_model._default_manager.__class__
       
   446         RelatedManager = create_many_related_manager(superclass)
       
   447 
       
   448         qn = connection.ops.quote_name
       
   449         manager = RelatedManager(
       
   450             model=rel_model,
       
   451             core_filters={'%s__pk' % self.related.field.name: instance._get_pk_val()},
       
   452             instance=instance,
       
   453             symmetrical=False,
       
   454             join_table=qn(self.related.field.m2m_db_table()),
       
   455             source_col_name=qn(self.related.field.m2m_reverse_name()),
       
   456             target_col_name=qn(self.related.field.m2m_column_name())
       
   457         )
       
   458 
       
   459         return manager
       
   460 
       
   461     def __set__(self, instance, value):
       
   462         if instance is None:
       
   463             raise AttributeError, "Manager must be accessed via instance"
       
   464 
       
   465         manager = self.__get__(instance)
       
   466         manager.clear()
       
   467         manager.add(*value)
       
   468 
       
   469 class ReverseManyRelatedObjectsDescriptor(object):
       
   470     # This class provides the functionality that makes the related-object
       
   471     # managers available as attributes on a model class, for fields that have
       
   472     # multiple "remote" values and have a ManyToManyField defined in their
       
   473     # model (rather than having another model pointed *at* them).
       
   474     # In the example "article.publications", the publications attribute is a
       
   475     # ReverseManyRelatedObjectsDescriptor instance.
       
   476     def __init__(self, m2m_field):
       
   477         self.field = m2m_field
       
   478 
       
   479     def __get__(self, instance, instance_type=None):
       
   480         if instance is None:
       
   481             raise AttributeError, "Manager must be accessed via instance"
       
   482 
       
   483         # Dynamically create a class that subclasses the related
       
   484         # model's default manager.
       
   485         rel_model=self.field.rel.to
       
   486         superclass = rel_model._default_manager.__class__
       
   487         RelatedManager = create_many_related_manager(superclass)
       
   488 
       
   489         qn = connection.ops.quote_name
       
   490         manager = RelatedManager(
       
   491             model=rel_model,
       
   492             core_filters={'%s__pk' % self.field.related_query_name(): instance._get_pk_val()},
       
   493             instance=instance,
       
   494             symmetrical=(self.field.rel.symmetrical and instance.__class__ == rel_model),
       
   495             join_table=qn(self.field.m2m_db_table()),
       
   496             source_col_name=qn(self.field.m2m_column_name()),
       
   497             target_col_name=qn(self.field.m2m_reverse_name())
       
   498         )
       
   499 
       
   500         return manager
       
   501 
       
   502     def __set__(self, instance, value):
       
   503         if instance is None:
       
   504             raise AttributeError, "Manager must be accessed via instance"
       
   505 
       
   506         manager = self.__get__(instance)
       
   507         manager.clear()
       
   508         manager.add(*value)
       
   509 
       
   510 class ManyToOneRel(object):
       
   511     def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None,
       
   512             max_num_in_admin=None, num_extra_on_change=1, edit_inline=False,
       
   513             related_name=None, limit_choices_to=None, lookup_overrides=None,
       
   514             raw_id_admin=False, parent_link=False):
       
   515         try:
       
   516             to._meta
       
   517         except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
       
   518             assert isinstance(to, basestring), "'to' must be either a model, a model name or the string %r" % RECURSIVE_RELATIONSHIP_CONSTANT
       
   519         self.to, self.field_name = to, field_name
       
   520         self.num_in_admin, self.edit_inline = num_in_admin, edit_inline
       
   521         self.min_num_in_admin, self.max_num_in_admin = min_num_in_admin, max_num_in_admin
       
   522         self.num_extra_on_change, self.related_name = num_extra_on_change, related_name
       
   523         if limit_choices_to is None:
       
   524             limit_choices_to = {}
       
   525         self.limit_choices_to = limit_choices_to
       
   526         self.lookup_overrides = lookup_overrides or {}
       
   527         self.raw_id_admin = raw_id_admin
       
   528         self.multiple = True
       
   529         self.parent_link = parent_link
       
   530 
       
   531     def get_related_field(self):
       
   532         """
       
   533         Returns the Field in the 'to' object to which this relationship is
       
   534         tied.
       
   535         """
       
   536         data = self.to._meta.get_field_by_name(self.field_name)
       
   537         if not data[2]:
       
   538             raise FieldDoesNotExist("No related field named '%s'" %
       
   539                     self.field_name)
       
   540         return data[0]
       
   541 
       
   542 class OneToOneRel(ManyToOneRel):
       
   543     def __init__(self, to, field_name, num_in_admin=0, min_num_in_admin=None,
       
   544             max_num_in_admin=None, num_extra_on_change=None, edit_inline=False,
       
   545             related_name=None, limit_choices_to=None, lookup_overrides=None,
       
   546             raw_id_admin=False, parent_link=False):
       
   547         # NOTE: *_num_in_admin and num_extra_on_change are intentionally
       
   548         # ignored here. We accept them as parameters only to match the calling
       
   549         # signature of ManyToOneRel.__init__().
       
   550         super(OneToOneRel, self).__init__(to, field_name, num_in_admin,
       
   551                 edit_inline=edit_inline, related_name=related_name,
       
   552                 limit_choices_to=limit_choices_to,
       
   553                 lookup_overrides=lookup_overrides, raw_id_admin=raw_id_admin,
       
   554                 parent_link=parent_link)
       
   555         self.multiple = False
       
   556 
       
   557 class ManyToManyRel(object):
       
   558     def __init__(self, to, num_in_admin=0, related_name=None,
       
   559         filter_interface=None, limit_choices_to=None, raw_id_admin=False, symmetrical=True):
       
   560         self.to = to
       
   561         self.num_in_admin = num_in_admin
       
   562         self.related_name = related_name
       
   563         self.filter_interface = filter_interface
       
   564         if limit_choices_to is None:
       
   565             limit_choices_to = {}
       
   566         self.limit_choices_to = limit_choices_to
       
   567         self.edit_inline = False
       
   568         self.raw_id_admin = raw_id_admin
       
   569         self.symmetrical = symmetrical
       
   570         self.multiple = True
       
   571 
       
   572         assert not (self.raw_id_admin and self.filter_interface), "ManyToManyRels may not use both raw_id_admin and filter_interface"
       
   573 
       
   574 class ForeignKey(RelatedField, Field):
       
   575     empty_strings_allowed = False
       
   576     def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs):
       
   577         try:
       
   578             to_name = to._meta.object_name.lower()
       
   579         except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
       
   580             assert isinstance(to, basestring), "%s(%r) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string %r" % (self.__class__.__name__, to, RECURSIVE_RELATIONSHIP_CONSTANT)
       
   581         else:
       
   582             to_field = to_field or to._meta.pk.name
       
   583         kwargs['verbose_name'] = kwargs.get('verbose_name', '')
       
   584 
       
   585         if 'edit_inline_type' in kwargs:
       
   586             import warnings
       
   587             warnings.warn("edit_inline_type is deprecated. Use edit_inline instead.", DeprecationWarning)
       
   588             kwargs['edit_inline'] = kwargs.pop('edit_inline_type')
       
   589 
       
   590         kwargs['rel'] = rel_class(to, to_field,
       
   591             num_in_admin=kwargs.pop('num_in_admin', 3),
       
   592             min_num_in_admin=kwargs.pop('min_num_in_admin', None),
       
   593             max_num_in_admin=kwargs.pop('max_num_in_admin', None),
       
   594             num_extra_on_change=kwargs.pop('num_extra_on_change', 1),
       
   595             edit_inline=kwargs.pop('edit_inline', False),
       
   596             related_name=kwargs.pop('related_name', None),
       
   597             limit_choices_to=kwargs.pop('limit_choices_to', None),
       
   598             lookup_overrides=kwargs.pop('lookup_overrides', None),
       
   599             raw_id_admin=kwargs.pop('raw_id_admin', False),
       
   600             parent_link=kwargs.pop('parent_link', False))
       
   601         Field.__init__(self, **kwargs)
       
   602 
       
   603         self.db_index = True
       
   604 
       
   605     def get_attname(self):
       
   606         return '%s_id' % self.name
       
   607 
       
   608     def get_validator_unique_lookup_type(self):
       
   609         return '%s__%s__exact' % (self.name, self.rel.get_related_field().name)
       
   610 
       
   611     def prepare_field_objs_and_params(self, manipulator, name_prefix):
       
   612         params = {'validator_list': self.validator_list[:], 'member_name': name_prefix + self.attname}
       
   613         if self.rel.raw_id_admin:
       
   614             field_objs = self.get_manipulator_field_objs()
       
   615             params['validator_list'].append(curry(manipulator_valid_rel_key, self, manipulator))
       
   616         else:
       
   617             if self.radio_admin:
       
   618                 field_objs = [oldforms.RadioSelectField]
       
   619                 params['ul_class'] = get_ul_class(self.radio_admin)
       
   620             else:
       
   621                 if self.null:
       
   622                     field_objs = [oldforms.NullSelectField]
       
   623                 else:
       
   624                     field_objs = [oldforms.SelectField]
       
   625             params['choices'] = self.get_choices_default()
       
   626         return field_objs, params
       
   627 
       
   628     def get_default(self):
       
   629         "Here we check if the default value is an object and return the to_field if so."
       
   630         field_default = super(ForeignKey, self).get_default()
       
   631         if isinstance(field_default, self.rel.to):
       
   632             return getattr(field_default, self.rel.get_related_field().attname)
       
   633         return field_default
       
   634 
       
   635     def get_manipulator_field_objs(self):
       
   636         rel_field = self.rel.get_related_field()
       
   637         if self.rel.raw_id_admin and not isinstance(rel_field, AutoField):
       
   638             return rel_field.get_manipulator_field_objs()
       
   639         else:
       
   640             return [oldforms.IntegerField]
       
   641 
       
   642     def get_db_prep_save(self, value):
       
   643         if value == '' or value == None:
       
   644             return None
       
   645         else:
       
   646             return self.rel.get_related_field().get_db_prep_save(value)
       
   647 
       
   648     def flatten_data(self, follow, obj=None):
       
   649         if not obj:
       
   650             # In required many-to-one fields with only one available choice,
       
   651             # select that one available choice. Note: For SelectFields
       
   652             # (radio_admin=False), we have to check that the length of choices
       
   653             # is *2*, not 1, because SelectFields always have an initial
       
   654             # "blank" value. Otherwise (radio_admin=True), we check that the
       
   655             # length is 1.
       
   656             if not self.blank and (not self.rel.raw_id_admin or self.choices):
       
   657                 choice_list = self.get_choices_default()
       
   658                 if self.radio_admin and len(choice_list) == 1:
       
   659                     return {self.attname: choice_list[0][0]}
       
   660                 if not self.radio_admin and len(choice_list) == 2:
       
   661                     return {self.attname: choice_list[1][0]}
       
   662         return Field.flatten_data(self, follow, obj)
       
   663 
       
   664     def contribute_to_class(self, cls, name):
       
   665         super(ForeignKey, self).contribute_to_class(cls, name)
       
   666         setattr(cls, self.name, ReverseSingleRelatedObjectDescriptor(self))
       
   667 
       
   668     def contribute_to_related_class(self, cls, related):
       
   669         setattr(cls, related.get_accessor_name(), ForeignRelatedObjectsDescriptor(related))
       
   670 
       
   671     def formfield(self, **kwargs):
       
   672         defaults = {'form_class': forms.ModelChoiceField, 'queryset': self.rel.to._default_manager.all()}
       
   673         defaults.update(kwargs)
       
   674         return super(ForeignKey, self).formfield(**defaults)
       
   675 
       
   676     def db_type(self):
       
   677         # The database column type of a ForeignKey is the column type
       
   678         # of the field to which it points. An exception is if the ForeignKey
       
   679         # points to an AutoField/PositiveIntegerField/PositiveSmallIntegerField,
       
   680         # in which case the column type is simply that of an IntegerField.
       
   681         rel_field = self.rel.get_related_field()
       
   682         if isinstance(rel_field, (AutoField, PositiveIntegerField, PositiveSmallIntegerField)):
       
   683             return IntegerField().db_type()
       
   684         return rel_field.db_type()
       
   685 
       
   686 class OneToOneField(ForeignKey):
       
   687     """
       
   688     A OneToOneField is essentially the same as a ForeignKey, with the exception
       
   689     that always carries a "unique" constraint with it and the reverse relation
       
   690     always returns the object pointed to (since there will only ever be one),
       
   691     rather than returning a list.
       
   692     """
       
   693     def __init__(self, to, to_field=None, **kwargs):
       
   694         kwargs['unique'] = True
       
   695         if 'num_in_admin' not in kwargs:
       
   696             kwargs['num_in_admin'] = 0
       
   697         super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs)
       
   698 
       
   699     def contribute_to_related_class(self, cls, related):
       
   700         setattr(cls, related.get_accessor_name(),
       
   701                 SingleRelatedObjectDescriptor(related))
       
   702         if not cls._meta.one_to_one_field:
       
   703             cls._meta.one_to_one_field = self
       
   704 
       
   705 class ManyToManyField(RelatedField, Field):
       
   706     def __init__(self, to, **kwargs):
       
   707         kwargs['verbose_name'] = kwargs.get('verbose_name', None)
       
   708         kwargs['rel'] = ManyToManyRel(to,
       
   709             num_in_admin=kwargs.pop('num_in_admin', 0),
       
   710             related_name=kwargs.pop('related_name', None),
       
   711             filter_interface=kwargs.pop('filter_interface', None),
       
   712             limit_choices_to=kwargs.pop('limit_choices_to', None),
       
   713             raw_id_admin=kwargs.pop('raw_id_admin', False),
       
   714             symmetrical=kwargs.pop('symmetrical', True))
       
   715         self.db_table = kwargs.pop('db_table', None)
       
   716         if kwargs["rel"].raw_id_admin:
       
   717             kwargs.setdefault("validator_list", []).append(self.isValidIDList)
       
   718         Field.__init__(self, **kwargs)
       
   719 
       
   720         if self.rel.raw_id_admin:
       
   721             msg = ugettext_lazy('Separate multiple IDs with commas.')
       
   722         else:
       
   723             msg = ugettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.')
       
   724         self.help_text = string_concat(self.help_text, ' ', msg)
       
   725 
       
   726     def get_manipulator_field_objs(self):
       
   727         if self.rel.raw_id_admin:
       
   728             return [oldforms.RawIdAdminField]
       
   729         else:
       
   730             choices = self.get_choices_default()
       
   731             return [curry(oldforms.SelectMultipleField, size=min(max(len(choices), 5), 15), choices=choices)]
       
   732 
       
   733     def get_choices_default(self):
       
   734         return Field.get_choices(self, include_blank=False)
       
   735 
       
   736     def _get_m2m_db_table(self, opts):
       
   737         "Function that can be curried to provide the m2m table name for this relation"
       
   738         if self.db_table:
       
   739             return self.db_table
       
   740         else:
       
   741             return '%s_%s' % (opts.db_table, self.name)
       
   742 
       
   743     def _get_m2m_column_name(self, related):
       
   744         "Function that can be curried to provide the source column name for the m2m table"
       
   745         # If this is an m2m relation to self, avoid the inevitable name clash
       
   746         if related.model == related.parent_model:
       
   747             return 'from_' + related.model._meta.object_name.lower() + '_id'
       
   748         else:
       
   749             return related.model._meta.object_name.lower() + '_id'
       
   750 
       
   751     def _get_m2m_reverse_name(self, related):
       
   752         "Function that can be curried to provide the related column name for the m2m table"
       
   753         # If this is an m2m relation to self, avoid the inevitable name clash
       
   754         if related.model == related.parent_model:
       
   755             return 'to_' + related.parent_model._meta.object_name.lower() + '_id'
       
   756         else:
       
   757             return related.parent_model._meta.object_name.lower() + '_id'
       
   758 
       
   759     def isValidIDList(self, field_data, all_data):
       
   760         "Validates that the value is a valid list of foreign keys"
       
   761         mod = self.rel.to
       
   762         try:
       
   763             pks = map(int, field_data.split(','))
       
   764         except ValueError:
       
   765             # the CommaSeparatedIntegerField validator will catch this error
       
   766             return
       
   767         objects = mod._default_manager.in_bulk(pks)
       
   768         if len(objects) != len(pks):
       
   769             badkeys = [k for k in pks if k not in objects]
       
   770             raise validators.ValidationError, ungettext("Please enter valid %(self)s IDs. The value %(value)r is invalid.",
       
   771                     "Please enter valid %(self)s IDs. The values %(value)r are invalid.", len(badkeys)) % {
       
   772                 'self': self.verbose_name,
       
   773                 'value': len(badkeys) == 1 and badkeys[0] or tuple(badkeys),
       
   774             }
       
   775 
       
   776     def flatten_data(self, follow, obj = None):
       
   777         new_data = {}
       
   778         if obj:
       
   779             instance_ids = [instance._get_pk_val() for instance in getattr(obj, self.name).all()]
       
   780             if self.rel.raw_id_admin:
       
   781                 new_data[self.name] = u",".join([smart_unicode(id) for id in instance_ids])
       
   782             else:
       
   783                 new_data[self.name] = instance_ids
       
   784         else:
       
   785             # In required many-to-many fields with only one available choice,
       
   786             # select that one available choice.
       
   787             if not self.blank and not self.rel.edit_inline and not self.rel.raw_id_admin:
       
   788                 choices_list = self.get_choices_default()
       
   789                 if len(choices_list) == 1:
       
   790                     new_data[self.name] = [choices_list[0][0]]
       
   791         return new_data
       
   792 
       
   793     def contribute_to_class(self, cls, name):
       
   794         super(ManyToManyField, self).contribute_to_class(cls, name)
       
   795         # Add the descriptor for the m2m relation
       
   796         setattr(cls, self.name, ReverseManyRelatedObjectsDescriptor(self))
       
   797 
       
   798         # Set up the accessor for the m2m table name for the relation
       
   799         self.m2m_db_table = curry(self._get_m2m_db_table, cls._meta)
       
   800 
       
   801     def contribute_to_related_class(self, cls, related):
       
   802         # m2m relations to self do not have a ManyRelatedObjectsDescriptor,
       
   803         # as it would be redundant - unless the field is non-symmetrical.
       
   804         if related.model != related.parent_model or not self.rel.symmetrical:
       
   805             # Add the descriptor for the m2m relation
       
   806             setattr(cls, related.get_accessor_name(), ManyRelatedObjectsDescriptor(related))
       
   807 
       
   808         # Set up the accessors for the column names on the m2m table
       
   809         self.m2m_column_name = curry(self._get_m2m_column_name, related)
       
   810         self.m2m_reverse_name = curry(self._get_m2m_reverse_name, related)
       
   811 
       
   812     def set_attributes_from_rel(self):
       
   813         pass
       
   814 
       
   815     def value_from_object(self, obj):
       
   816         "Returns the value of this field in the given model instance."
       
   817         return getattr(obj, self.attname).all()
       
   818 
       
   819     def save_form_data(self, instance, data):
       
   820         setattr(instance, self.attname, data)
       
   821 
       
   822     def formfield(self, **kwargs):
       
   823         defaults = {'form_class': forms.ModelMultipleChoiceField, 'queryset': self.rel.to._default_manager.all()}
       
   824         defaults.update(kwargs)
       
   825         # If initial is passed in, it's a list of related objects, but the
       
   826         # MultipleChoiceField takes a list of IDs.
       
   827         if defaults.get('initial') is not None:
       
   828             defaults['initial'] = [i._get_pk_val() for i in defaults['initial']]
       
   829         return super(ManyToManyField, self).formfield(**defaults)
       
   830 
       
   831     def db_type(self):
       
   832         # A ManyToManyField is not represented by a single column,
       
   833         # so return None.
       
   834         return None
       
   835