Django

Code

root/django/trunk/django/db/models/fields/related.py

Revision 11009, 44.1 kB (checked in by russellm, 3 weeks ago)

Fixed #9023 -- Corrected a problem where cached attribute values would cause a delete to cascade to a related object even when the relationship had been set to None. Thanks to TheShark? for the report and test case, and to juriejan and Jacob for their work on the patch.

  • Property svn:eol-style set to native
Line 
1 from django.db import connection, transaction
2 from django.db.backends import util
3 from django.db.models import signals, get_model
4 from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist
5 from django.db.models.related import RelatedObject
6 from django.db.models.query import QuerySet
7 from django.db.models.query_utils import QueryWrapper
8 from django.utils.encoding import smart_unicode
9 from django.utils.translation import ugettext_lazy, string_concat, ungettext, ugettext as _
10 from django.utils.functional import curry
11 from django.core import exceptions
12 from django import forms
13
14 try:
15     set
16 except NameError:
17     from sets import Set as set   # Python 2.3 fallback
18
19 RECURSIVE_RELATIONSHIP_CONSTANT = 'self'
20
21 pending_lookups = {}
22
23 def add_lazy_relation(cls, field, relation, operation):
24     """
25     Adds a lookup on ``cls`` when a related field is defined using a string,
26     i.e.::
27
28         class MyModel(Model):
29             fk = ForeignKey("AnotherModel")
30
31     This string can be:
32
33         * RECURSIVE_RELATIONSHIP_CONSTANT (i.e. "self") to indicate a recursive
34           relation.
35
36         * The name of a model (i.e "AnotherModel") to indicate another model in
37           the same app.
38
39         * An app-label and model name (i.e. "someapp.AnotherModel") to indicate
40           another model in a different app.
41
42     If the other model hasn't yet been loaded -- almost a given if you're using
43     lazy relationships -- then the relation won't be set up until the
44     class_prepared signal fires at the end of model initialization.
45
46     operation is the work that must be performed once the relation can be resolved.
47     """
48     # Check for recursive relations
49     if relation == RECURSIVE_RELATIONSHIP_CONSTANT:
50         app_label = cls._meta.app_label
51         model_name = cls.__name__
52
53     else:
54         # Look for an "app.Model" relation
55         try:
56             app_label, model_name = relation.split(".")
57         except ValueError:
58             # If we can't split, assume a model in current app
59             app_label = cls._meta.app_label
60             model_name = relation
61
62     # Try to look up the related model, and if it's already loaded resolve the
63     # string right away. If get_model returns None, it means that the related
64     # model isn't loaded yet, so we need to pend the relation until the class
65     # is prepared.
66     model = get_model(app_label, model_name, False)
67     if model:
68         operation(field, model, cls)
69     else:
70         key = (app_label, model_name)
71         value = (cls, field, operation)
72         pending_lookups.setdefault(key, []).append(value)
73
74 def do_pending_lookups(sender, **kwargs):
75     """
76     Handle any pending relations to the sending model. Sent from class_prepared.
77     """
78     key = (sender._meta.app_label, sender.__name__)
79     for cls, field, operation in pending_lookups.pop(key, []):
80         operation(field, sender, cls)
81
82 signals.class_prepared.connect(do_pending_lookups)
83
84 #HACK
85 class RelatedField(object):
86     def contribute_to_class(self, cls, name):
87         sup = super(RelatedField, self)
88
89         # Add an accessor to allow easy determination of the related query path for this field
90         self.related_query_name = curry(self._get_related_query_name, cls._meta)
91
92         if hasattr(sup, 'contribute_to_class'):
93             sup.contribute_to_class(cls, name)
94
95         if not cls._meta.abstract and self.rel.related_name:
96             self.rel.related_name = self.rel.related_name % {'class': cls.__name__.lower()}
97
98         other = self.rel.to
99         if isinstance(other, basestring):
100             def resolve_related_class(field, model, cls):
101                 field.rel.to = model
102                 field.do_related_class(model, cls)
103             add_lazy_relation(cls, self, other, resolve_related_class)
104         else:
105             self.do_related_class(other, cls)
106
107     def set_attributes_from_rel(self):
108         self.name = self.name or (self.rel.to._meta.object_name.lower() + '_' + self.rel.to._meta.pk.name)
109         if self.verbose_name is None:
110             self.verbose_name = self.rel.to._meta.verbose_name
111         self.rel.field_name = self.rel.field_name or self.rel.to._meta.pk.name
112
113     def do_related_class(self, other, cls):
114         self.set_attributes_from_rel()
115         self.related = RelatedObject(other, cls, self)
116         if not cls._meta.abstract:
117             self.contribute_to_related_class(other, self.related)
118
119     def get_db_prep_lookup(self, lookup_type, value):
120         # If we are doing a lookup on a Related Field, we must be
121         # comparing object instances. The value should be the PK of value,
122         # not value itself.
123         def pk_trace(value):
124             # Value may be a primary key, or an object held in a relation.
125             # If it is an object, then we need to get the primary key value for
126             # that object. In certain conditions (especially one-to-one relations),
127             # the primary key may itself be an object - so we need to keep drilling
128             # down until we hit a value that can be used for a comparison.
129             v, field = value, None
130             try:
131                 while True:
132                     v, field = getattr(v, v._meta.pk.name), v._meta.pk
133             except AttributeError:
134                 pass
135
136             if field:
137                 if lookup_type in ('range', 'in'):
138                     v = [v]
139                 v = field.get_db_prep_lookup(lookup_type, v)
140                 if isinstance(v, list):
141                     v = v[0]
142             return v
143
144         if hasattr(value, 'as_sql') or hasattr(value, '_as_sql'):
145             # If the value has a relabel_aliases method, it will need to
146             # be invoked before the final SQL is evaluated
147             if hasattr(value, 'relabel_aliases'):
148                 return value
149             if hasattr(value, 'as_sql'):
150                 sql, params = value.as_sql()
151             else:
152                 sql, params = value._as_sql()
153             return QueryWrapper(('(%s)' % sql), params)
154
155         # FIXME: lt and gt are explicitally allowed to make
156         # get_(next/prev)_by_date work; other lookups are not allowed since that
157         # gets messy pretty quick. This is a good candidate for some refactoring
158         # in the future.
159         if lookup_type in ['exact', 'gt', 'lt', 'gte', 'lte']:
160             return [pk_trace(value)]
161         if lookup_type in ('range', 'in'):
162             return [pk_trace(v) for v in value]
163         elif lookup_type == 'isnull':
164             return []
165         raise TypeError, "Related Field has invalid lookup: %s" % lookup_type
166
167     def _get_related_query_name(self, opts):
168         # This method defines the name that can be used to identify this
169         # related object in a table-spanning query. It uses the lower-cased
170         # object_name by default, but this can be overridden with the
171         # "related_name" option.
172         return self.rel.related_name or opts.object_name.lower()
173
174 class SingleRelatedObjectDescriptor(object):
175     # This class provides the functionality that makes the related-object
176     # managers available as attributes on a model class, for fields that have
177     # a single "remote" value, on the class pointed to by a related field.
178     # In the example "place.restaurant", the restaurant attribute is a
179     # SingleRelatedObjectDescriptor instance.
180     def __init__(self, related):
181         self.related = related
182         self.cache_name = '_%s_cache' % related.get_accessor_name()
183
184     def __get__(self, instance, instance_type=None):
185         if instance is None:
186             return self
187         try:
188             return getattr(instance, self.cache_name)
189         except AttributeError:
190             params = {'%s__pk' % self.related.field.name: instance._get_pk_val()}
191             rel_obj = self.related.model._base_manager.get(**params)
192             setattr(instance, self.cache_name, rel_obj)
193             return rel_obj
194
195     def __set__(self, instance, value):
196         if instance is None:
197             raise AttributeError, "%s must be accessed via instance" % self.related.opts.object_name
198
199         # The similarity of the code below to the code in
200         # ReverseSingleRelatedObjectDescriptor is annoying, but there's a bunch
201         # of small differences that would make a common base class convoluted.
202
203         # If null=True, we can assign null here, but otherwise the value needs
204         # to be an instance of the related class.
205         if value is None and self.related.field.null == False:
206             raise ValueError('Cannot assign None: "%s.%s" does not allow null values.' %
207                                 (instance._meta.object_name, self.related.get_accessor_name()))
208         elif value is not None and not isinstance(value, self.related.model):
209             raise ValueError('Cannot assign "%r": "%s.%s" must be a "%s" instance.' %
210                                 (value, instance._meta.object_name,
211                                  self.related.get_accessor_name(), self.related.opts.object_name))
212
213         # Set the value of the related field to the value of the related object's related field
214         setattr(value, self.related.field.attname, getattr(instance, self.related.field.rel.get_related_field().attname))
215
216         # Since we already know what the related object is, seed the related
217         # object caches now, too. This avoids another db hit if you get the
218         # object you just set.
219         setattr(instance, self.cache_name, value)
220         setattr(value, self.related.field.get_cache_name(), instance)
221
222 class ReverseSingleRelatedObjectDescriptor(object):
223     # This class provides the functionality that makes the related-object
224     # managers available as attributes on a model class, for fields that have
225     # a single "remote" value, on the class that defines the related field.
226     # In the example "choice.poll", the poll attribute is a
227     # ReverseSingleRelatedObjectDescriptor instance.
228     def __init__(self, field_with_rel):
229         self.field = field_with_rel
230
231     def __get__(self, instance, instance_type=None):
232         if instance is None:
233             return self
234
235         cache_name = self.field.get_cache_name()
236         try:
237             return getattr(instance, cache_name)
238         except AttributeError:
239             val = getattr(instance, self.field.attname)
240             if val is None:
241                 # If NULL is an allowed value, return it.
242                 if self.field.null:
243                     return None
244                 raise self.field.rel.to.DoesNotExist
245             other_field = self.field.rel.get_related_field()
246             if other_field.rel:
247                 params = {'%s__pk' % self.field.rel.field_name: val}
248             else:
249                 params = {'%s__exact' % self.field.rel.field_name: val}
250
251             # If the related manager indicates that it should be used for
252             # related fields, respect that.
253             rel_mgr = self.field.rel.to._default_manager
254             if getattr(rel_mgr, 'use_for_related_fields', False):
255                 rel_obj = rel_mgr.get(**params)
256             else:
257                 rel_obj = QuerySet(self.field.rel.to).get(**params)
258             setattr(instance, cache_name, rel_obj)
259             return rel_obj
260
261     def __set__(self, instance, value):
262         if instance is None:
263             raise AttributeError, "%s must be accessed via instance" % self._field.name
264
265         # If null=True, we can assign null here, but otherwise the value needs
266         # to be an instance of the related class.
267         if value is None and self.field.null == False:
268             raise ValueError('Cannot assign None: "%s.%s" does not allow null values.' %
269                                 (instance._meta.object_name, self.field.name))
270         elif value is not None and not isinstance(value, self.field.rel.to):
271             raise ValueError('Cannot assign "%r": "%s.%s" must be a "%s" instance.' %
272                                 (value, instance._meta.object_name,
273                                  self.field.name, self.field.rel.to._meta.object_name))
274
275         # If we're setting the value of a OneToOneField to None, we need to clear
276         # out the cache on any old related object. Otherwise, deleting the
277         # previously-related object will also cause this object to be deleted,
278         # which is wrong.
279         if value is None:
280             # Look up the previously-related object, which may still be available
281             # since we've not yet cleared out the related field.
282             # Use the cache directly, instead of the accessor; if we haven't
283             # populated the cache, then we don't care - we're only accessing
284             # the object to invalidate the accessor cache, so there's no
285             # need to populate the cache just to expire it again.
286             related = getattr(instance, self.field.get_cache_name(), None)
287
288             # If we've got an old related object, we need to clear out its
289             # cache. This cache also might not exist if the related object
290             # hasn't been accessed yet.
291             if related:
292                 cache_name = '_%s_cache' % self.field.related.get_accessor_name()
293                 try:
294                     delattr(related, cache_name)
295                 except AttributeError:
296                     pass
297
298         # Set the value of the related field
299         try:
300             val = getattr(value, self.field.rel.get_related_field().attname)
301         except AttributeError:
302             val = None
303         setattr(instance, self.field.attname, val)
304
305         # Since we already know what the related object is, seed the related
306         # object cache now, too. This avoids another db hit if you get the
307         # object you just set.
308         setattr(instance, self.field.get_cache_name(), value)
309
310 class ForeignRelatedObjectsDescriptor(object):
311     # This class provides the functionality that makes the related-object
312     # managers available as attributes on a model class, for fields that have
313     # multiple "remote" values and have a ForeignKey pointed at them by
314     # some other model. In the example "poll.choice_set", the choice_set
315     # attribute is a ForeignRelatedObjectsDescriptor instance.
316     def __init__(self, related):
317         self.related = related   # RelatedObject instance
318
319     def __get__(self, instance, instance_type=None):
320         if instance is None:
321             return self
322
323         return self.create_manager(instance,
324                 self.related.model._default_manager.__class__)
325
326     def __set__(self, instance, value):
327         if instance is None:
328             raise AttributeError, "Manager must be accessed via instance"
329
330         manager = self.__get__(instance)
331         # If the foreign key can support nulls, then completely clear the related set.
332         # Otherwise, just move the named objects into the set.
333         if self.related.field.null:
334             manager.clear()
335         manager.add(*value)
336
337     def delete_manager(self, instance):
338         """
339         Returns a queryset based on the related model's base manager (rather
340         than the default manager, as returned by __get__). Used by
341         Model.delete().
342         """
343         return self.create_manager(instance,
344                 self.related.model._base_manager.__class__)
345
346     def create_manager(self, instance, superclass):
347         """
348         Creates the managers used by other methods (__get__() and delete()).
349         """
350         rel_field = self.related.field
351         rel_model = self.related.model
352
353         class RelatedManager(superclass):
354             def get_query_set(self):
355                 return superclass.get_query_set(self).filter(**(self.core_filters))
356
357             def add(self, *objs):
358                 for obj in objs:
359                     if not isinstance(obj, self.model):
360                         raise TypeError, "'%s' instance expected" % self.model._meta.object_name
361                     setattr(obj, rel_field.name, instance)
362                     obj.save()
363             add.alters_data = True
364
365             def create(self, **kwargs):
366                 kwargs.update({rel_field.name: instance})
367                 return super(RelatedManager, self).create(**kwargs)
368             create.alters_data = True
369
370             def get_or_create(self, **kwargs):
371                 # Update kwargs with the related object that this
372                 # ForeignRelatedObjectsDescriptor knows about.
373                 kwargs.update({rel_field.name: instance})
374                 return super(RelatedManager, self).get_or_create(**kwargs)
375             get_or_create.alters_data = True
376
377             # remove() and clear() are only provided if the ForeignKey can have a value of null.
378             if rel_field.null:
379                 def remove(self, *objs):
380                     val = getattr(instance, rel_field.rel.get_related_field().attname)
381                     for obj in objs:
382                         # Is obj actually part of this descriptor set?
383                         if getattr(obj, rel_field.attname) == val:
384                             setattr(obj, rel_field.name, None)
385                             obj.save()
386                         else:
387                             raise rel_field.rel.to.DoesNotExist, "%r is not related to %r." % (obj, instance)
388                 remove.alters_data = True
389
390                 def clear(self):
391                     for obj in self.all():
392                         setattr(obj, rel_field.name, None)
393                         obj.save()
394                 clear.alters_data = True
395
396         manager = RelatedManager()
397         attname = rel_field.rel.get_related_field().name
398         manager.core_filters = {'%s__%s' % (rel_field.name, attname):
399                 getattr(instance, attname)}
400         manager.model = self.related.model
401
402         return manager
403
404 def create_many_related_manager(superclass, through=False):
405     """Creates a manager that subclasses 'superclass' (which is a Manager)
406     and adds behavior for many-to-many related objects."""
407     class ManyRelatedManager(superclass):
408         def __init__(self, model=None, core_filters=None, instance=None, symmetrical=None,
409                 join_table=None, source_col_name=None, target_col_name=None):
410             super(ManyRelatedManager, self).__init__()
411             self.core_filters = core_filters
412             self.model = model
413             self.symmetrical = symmetrical
414             self.instance = instance
415             self.join_table = join_table
416             self.source_col_name = source_col_name
417             self.target_col_name = target_col_name
418             self.through = through
419             self._pk_val = self.instance._get_pk_val()
420             if self._pk_val is None:
421                 raise ValueError("%r instance needs to have a primary key value before a many-to-many relationship can be used." % instance.__class__.__name__)
422
423         def get_query_set(self):
424             return superclass.get_query_set(self)._next_is_sticky().filter(**(self.core_filters))
425
426         # If the ManyToMany relation has an intermediary model,
427         # the add and remove methods do not exist.
428         if through is None:
429             def add(self, *objs):
430                 self._add_items(self.source_col_name, self.target_col_name, *objs)
431
432                 # If this is a symmetrical m2m relation to self, add the mirror entry in the m2m table
433                 if self.symmetrical:
434                     self._add_items(self.target_col_name, self.source_col_name, *objs)
435             add.alters_data = True
436
437             def remove(self, *objs):
438                 self._remove_items(self.source_col_name, self.target_col_name, *objs)
439
440                 # If this is a symmetrical m2m relation to self, remove the mirror entry in the m2m table
441                 if self.symmetrical:
442                     self._remove_items(self.target_col_name, self.source_col_name, *objs)
443             remove.alters_data = True
444
445         def clear(self):
446             self._clear_items(self.source_col_name)
447
448             # If this is a symmetrical m2m relation to self, clear the mirror entry in the m2m table
449             if self.symmetrical:
450                 self._clear_items(self.target_col_name)
451         clear.alters_data = True
452
453         def create(self, **kwargs):
454             # This check needs to be done here, since we can't later remove this
455             # from the method lookup table, as we do with add and remove.
456             if through is not None:
457                 raise AttributeError, "Cannot use create() on a ManyToManyField which specifies an intermediary model. Use %s's Manager instead." % through
458             new_obj = super(ManyRelatedManager, self).create(**kwargs)
459             self.add(new_obj)
460             return new_obj
461         create.alters_data = True
462
463         def get_or_create(self, **kwargs):
464             obj, created = \
465                     super(ManyRelatedManager, self).get_or_create(**kwargs)
466             # We only need to add() if created because if we got an object back
467             # from get() then the relationship already exists.
468             if created:
469                 self.add(obj)
470             return obj, created
471         get_or_create.alters_data = True
472
473         def _add_items(self, source_col_name, target_col_name, *objs):
474             # join_table: name of the m2m link table
475             # source_col_name: the PK colname in join_table for the source object
476             # target_col_name: the PK colname in join_table for the target object
477             # *objs - objects to add. Either object instances, or primary keys of object instances.
478
479             # If there aren't any objects, there is nothing to do.
480             if objs:
481                 from django.db.models.base import Model
482                 # Check that all the objects are of the right type
483                 new_ids = set()
484                 for obj in objs:
485                     if isinstance(obj, self.model):
486                         new_ids.add(obj._get_pk_val())
487                     elif isinstance(obj, Model):
488                         raise TypeError, "'%s' instance expected" % self.model._meta.object_name
489                     else:
490                         new_ids.add(obj)
491                 # Add the newly created or already existing objects to the join table.
492                 # First find out which items are already added, to avoid adding them twice
493                 cursor = connection.cursor()
494                 cursor.execute("SELECT %s FROM %s WHERE %s = %%s AND %s IN (%s)" % \
495                     (target_col_name, self.join_table, source_col_name,
496                     target_col_name, ",".join(['%s'] * len(new_ids))),
497                     [self._pk_val] + list(new_ids))
498                 existing_ids = set([row[0] for row in cursor.fetchall()])
499
500                 # Add the ones that aren't there already
501                 for obj_id in (new_ids - existing_ids):
502                     cursor.execute("INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \
503                         (self.join_table, source_col_name, target_col_name),
504                         [self._pk_val, obj_id])
505                 transaction.commit_unless_managed()
506
507         def _remove_items(self, source_col_name, target_col_name, *objs):
508             # source_col_name: the PK colname in join_table for the source object
509             # target_col_name: the PK colname in join_table for the target object
510             # *objs - objects to remove
511
512             # If there aren't any objects, there is nothing to do.
513             if objs:
514                 # Check that all the objects are of the right type
515                 old_ids = set()
516                 for obj in objs:
517                     if isinstance(obj, self.model):
518                         old_ids.add(obj._get_pk_val())
519                     else:
520                         old_ids.add(obj)
521                 # Remove the specified objects from the join table
522                 cursor = connection.cursor()
523                 cursor.execute("DELETE FROM %s WHERE %s = %%s AND %s IN (%s)" % \
524                     (self.join_table, source_col_name,
525                     target_col_name, ",".join(['%s'] * len(old_ids))),
526                     [self._pk_val] + list(old_ids))
527                 transaction.commit_unless_managed()
528
529         def _clear_items(self, source_col_name):
530             # source_col_name: the PK colname in join_table for the source object
531             cursor = connection.cursor()
532             cursor.execute("DELETE FROM %s WHERE %s = %%s" % \
533                 (self.join_table, source_col_name),
534                 [self._pk_val])
535             transaction.commit_unless_managed()
536
537     return ManyRelatedManager
538
539 class ManyRelatedObjectsDescriptor(object):
540     # This class provides the functionality that makes the related-object
541     # managers available as attributes on a model class, for fields that have
542     # multiple "remote" values and have a ManyToManyField pointed at them by
543     # some other model (rather than having a ManyToManyField themselves).
544     # In the example "publication.article_set", the article_set attribute is a
545     # ManyRelatedObjectsDescriptor instance.
546     def __init__(self, related):
547         self.related = related   # RelatedObject instance
548
549     def __get__(self, instance, instance_type=None):
550         if instance is None:
551             return self
552
553         # Dynamically create a class that subclasses the related
554         # model's default manager.
555         rel_model = self.related.model
556         superclass = rel_model._default_manager.__class__
557         RelatedManager = create_many_related_manager(superclass, self.related.field.rel.through)
558
559         qn = connection.ops.quote_name
560         manager = RelatedManager(
561             model=rel_model,
562             core_filters={'%s__pk' % self.related.field.name: instance._get_pk_val()},
563             instance=instance,
564             symmetrical=False,
565             join_table=qn(self.related.field.m2m_db_table()),
566             source_col_name=qn(self.related.field.m2m_reverse_name()),
567             target_col_name=qn(self.related.field.m2m_column_name())
568         )
569
570         return manager
571
572     def __set__(self, instance, value):
573         if instance is None:
574             raise AttributeError, "Manager must be accessed via instance"
575
576         through = getattr(self.related.field.rel, 'through', None)
577         if through is not None:
578             raise AttributeError, "Cannot set values on a ManyToManyField which specifies an intermediary model. Use %s's Manager instead." % through
579
580         manager = self.__get__(instance)
581         manager.clear()
582         manager.add(*value)
583
584 class ReverseManyRelatedObjectsDescriptor(object):
585     # This class provides the functionality that makes the related-object
586     # managers available as attributes on a model class, for fields that have
587     # multiple "remote" values and have a ManyToManyField defined in their
588     # model (rather than having another model pointed *at* them).
589     # In the example "article.publications", the publications attribute is a
590     # ReverseManyRelatedObjectsDescriptor instance.
591     def __init__(self, m2m_field):
592         self.field = m2m_field
593
594     def __get__(self, instance, instance_type=None):
595         if instance is None:
596             return self
597
598         # Dynamically create a class that subclasses the related
599         # model's default manager.
600         rel_model=self.field.rel.to
601         superclass = rel_model._default_manager.__class__
602         RelatedManager = create_many_related_manager(superclass, self.field.rel.through)
603
604         qn = connection.ops.quote_name
605         manager = RelatedManager(
606             model=rel_model,
607             core_filters={'%s__pk' % self.field.related_query_name(): instance._get_pk_val()},
608             instance=instance,
609             symmetrical=(self.field.rel.symmetrical and isinstance(instance, rel_model)),
610             join_table=qn(self.field.m2m_db_table()),
611             source_col_name=qn(self.field.m2m_column_name()),
612             target_col_name=qn(self.field.m2m_reverse_name())
613         )
614
615         return manager
616
617     def __set__(self, instance, value):
618         if instance is None:
619             raise AttributeError, "Manager must be accessed via instance"
620
621         through = getattr(self.field.rel, 'through', None)
622         if through is not None:
623             raise AttributeError, "Cannot set values on a ManyToManyField which specifies an intermediary model.  Use %s's Manager instead." % through
624
625         manager = self.__get__(instance)
626         manager.clear()
627         manager.add(*value)
628
629 class ManyToOneRel(object):
630     def __init__(self, to, field_name, related_name=None,
631             limit_choices_to=None, lookup_overrides=None, parent_link=False):
632         try:
633             to._meta
634         except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
635             assert isinstance(to, basestring), "'to' must be either a model, a model name or the string %r" % RECURSIVE_RELATIONSHIP_CONSTANT
636         self.to, self.field_name = to, field_name
637         self.related_name = related_name
638         if limit_choices_to is None:
639             limit_choices_to = {}
640         self.limit_choices_to = limit_choices_to
641         self.lookup_overrides = lookup_overrides or {}
642         self.multiple = True
643         self.parent_link = parent_link
644
645     def get_related_field(self):
646         """
647         Returns the Field in the 'to' object to which this relationship is
648         tied.
649         """
650         data = self.to._meta.get_field_by_name(self.field_name)
651         if not data[2]:
652             raise FieldDoesNotExist("No related field named '%s'" %
653                     self.field_name)
654         return data[0]
655
656 class OneToOneRel(ManyToOneRel):
657     def __init__(self, to, field_name, related_name=None,
658             limit_choices_to=None, lookup_overrides=None, parent_link=False):
659         super(OneToOneRel, self).__init__(to, field_name,
660                 related_name=related_name, limit_choices_to=limit_choices_to,
661                 lookup_overrides=lookup_overrides, parent_link=parent_link)
662         self.multiple = False
663
664 class ManyToManyRel(object):
665     def __init__(self, to, related_name=None, limit_choices_to=None,
666             symmetrical=True, through=None):
667         self.to = to
668         self.related_name = related_name
669         if limit_choices_to is None:
670             limit_choices_to = {}
671         self.limit_choices_to = limit_choices_to
672         self.symmetrical = symmetrical
673         self.multiple = True
674         self.through = through
675
676     def get_related_field(self):
677         """
678         Returns the field in the to' object to which this relationship is tied
679         (this is always the primary key on the target model). Provided for
680         symmetry with ManyToOneRel.
681         """
682         return self.to._meta.pk
683
684 class ForeignKey(RelatedField, Field):
685     empty_strings_allowed = False
686     def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs):
687         try:
688             to_name = to._meta.object_name.lower()
689         except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
690             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)
691         else:
692             assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name)
693             to_field = to_field or to._meta.pk.name
694         kwargs['verbose_name'] = kwargs.get('verbose_name', None)
695
696         kwargs['rel'] = rel_class(to, to_field,
697             related_name=kwargs.pop('related_name', None),
698             limit_choices_to=kwargs.pop('limit_choices_to', None),
699             lookup_overrides=kwargs.pop('lookup_overrides', None),
700             parent_link=kwargs.pop('parent_link', False))
701         Field.__init__(self, **kwargs)
702
703         self.db_index = True
704
705     def get_attname(self):
706         return '%s_id' % self.name
707
708     def get_validator_unique_lookup_type(self):
709         return '%s__%s__exact' % (self.name, self.rel.get_related_field().name)
710
711     def get_default(self):
712         "Here we check if the default value is an object and return the to_field if so."
713         field_default = super(ForeignKey, self).get_default()
714         if isinstance(field_default, self.rel.to):
715             return getattr(field_default, self.rel.get_related_field().attname)
716         return field_default
717
718     def get_db_prep_save(self, value):
719         if value == '' or value == None:
720             return None
721         else:
722             return self.rel.get_related_field().get_db_prep_save(value)
723
724     def value_to_string(self, obj):
725         if not obj:
726             # In required many-to-one fields with only one available choice,
727             # select that one available choice. Note: For SelectFields
728             # we have to check that the length of choices is *2*, not 1,
729             # because SelectFields always have an initial "blank" value.
730             if not self.blank and self.choices:
731                 choice_list = self.get_choices_default()
732                 if len(choice_list) == 2:
733                     return smart_unicode(choice_list[1][0])
734         return Field.value_to_string(self, obj)
735
736     def contribute_to_class(self, cls, name):
737         super(ForeignKey, self).contribute_to_class(cls, name)
738         setattr(cls, self.name, ReverseSingleRelatedObjectDescriptor(self))
739         if isinstance(self.rel.to, basestring):
740             target = self.rel.to
741         else:
742             target = self.rel.to._meta.db_table
743         cls._meta.duplicate_targets[self.column] = (target, "o2m")
744
745     def contribute_to_related_class(self, cls, related):
746         setattr(cls, related.get_accessor_name(), ForeignRelatedObjectsDescriptor(related))
747
748     def formfield(self, **kwargs):
749         defaults = {
750             'form_class': forms.ModelChoiceField,
751             'queryset': self.rel.to._default_manager.complex_filter(
752                                                     self.rel.limit_choices_to),
753             'to_field_name': self.rel.field_name,
754         }
755         defaults.update(kwargs)
756         return super(ForeignKey, self).formfield(**defaults)
757
758     def db_type(self):
759         # The database column type of a ForeignKey is the column type
760         # of the field to which it points. An exception is if the ForeignKey
761         # points to an AutoField/PositiveIntegerField/PositiveSmallIntegerField,
762         # in which case the column type is simply that of an IntegerField.
763         # If the database needs similar types for key fields however, the only
764         # thing we can do is making AutoField an IntegerField.
765         rel_field = self.rel.get_related_field()
766         if (isinstance(rel_field, AutoField) or
767                 (not connection.features.related_fields_match_type and
768                 isinstance(rel_field, (PositiveIntegerField,
769                                        PositiveSmallIntegerField)))):
770             return IntegerField().db_type()
771         return rel_field.db_type()
772
773 class OneToOneField(ForeignKey):
774     """
775     A OneToOneField is essentially the same as a ForeignKey, with the exception
776     that always carries a "unique" constraint with it and the reverse relation
777     always returns the object pointed to (since there will only ever be one),
778     rather than returning a list.
779     """
780     def __init__(self, to, to_field=None, **kwargs):
781         kwargs['unique'] = True
782         super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs)
783
784     def contribute_to_related_class(self, cls, related):
785         setattr(cls, related.get_accessor_name(),
786                 SingleRelatedObjectDescriptor(related))
787
788     def formfield(self, **kwargs):
789         if self.rel.parent_link:
790             return None
791         return super(OneToOneField, self).formfield(**kwargs)
792
793 class ManyToManyField(RelatedField, Field):
794     def __init__(self, to, **kwargs):
795         try:
796             assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name)
797         except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
798             assert isinstance(to, basestring), "%s(%r) is invalid. First parameter to ManyToManyField must be either a model, a model name, or the string %r" % (self.__class__.__name__, to, RECURSIVE_RELATIONSHIP_CONSTANT)
799
800         kwargs['verbose_name'] = kwargs.get('verbose_name', None)
801         kwargs['rel'] = ManyToManyRel(to,
802             related_name=kwargs.pop('related_name', None),
803             limit_choices_to=kwargs.pop('limit_choices_to', None),
804             symmetrical=kwargs.pop('symmetrical', True),
805             through=kwargs.pop('through', None))
806
807         self.db_table = kwargs.pop('db_table', None)
808         if kwargs['rel'].through is not None:
809             self.creates_table = False
810             assert self.db_table is None, "Cannot specify a db_table if an intermediary model is used."
811         else:
812             self.creates_table = True
813
814         Field.__init__(self, **kwargs)
815
816         msg = ugettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.')
817         self.help_text = string_concat(self.help_text, ' ', msg)
818
819     def get_choices_default(self):
820         return Field.get_choices(self, include_blank=False)
821
822     def _get_m2m_db_table(self, opts):
823         "Function that can be curried to provide the m2m table name for this relation"
824         if self.rel.through is not None:
825             return self.rel.through_model._meta.db_table
826         elif self.db_table:
827             return self.db_table
828         else:
829             return util.truncate_name('%s_%s' % (opts.db_table, self.name),
830                                       connection.ops.max_name_length())
831
832     def _get_m2m_column_name(self, related):
833         "Function that can be curried to provide the source column name for the m2m table"
834         try:
835             return self._m2m_column_name_cache
836         except:
837             if self.rel.through is not None:
838                 for f in self.rel.through_model._meta.fields:
839                     if hasattr(f,'rel') and f.rel and f.rel.to == related.model:
840                         self._m2m_column_name_cache = f.column
841                         break
842             # If this is an m2m relation to self, avoid the inevitable name clash
843             elif related.model == related.parent_model:
844                 self._m2m_column_name_cache = 'from_' + related.model._meta.object_name.lower() + '_id'
845             else:
846                 self._m2m_column_name_cache = related.model._meta.object_name.lower() + '_id'
847
848             # Return the newly cached value
849             return self._m2m_column_name_cache
850
851     def _get_m2m_reverse_name(self, related):
852         "Function that can be curried to provide the related column name for the m2m table"
853         try:
854             return self._m2m_reverse_name_cache
855         except:
856             if self.rel.through is not None:
857                 found = False
858                 for f in self.rel.through_model._meta.fields:
859                     if hasattr(f,'rel') and f.rel and f.rel.to == related.parent_model:
860                         if related.model == related.parent_model:
861                             # If this is an m2m-intermediate to self,
862                             # the first foreign key you find will be
863                             # the source column. Keep searching for
864                             # the second foreign key.
865                             if found:
866                                 self._m2m_reverse_name_cache = f.column
867                                 break
868                             else:
869                                 found = True
870                         else:
871                             self._m2m_reverse_name_cache = f.column
872                             break
873             # If this is an m2m relation to self, avoid the inevitable name clash
874             elif related.model == related.parent_model:
875                 self._m2m_reverse_name_cache = 'to_' + related.parent_model._meta.object_name.lower() + '_id'
876             else:
877                 self._m2m_reverse_name_cache = related.parent_model._meta.object_name.lower() + '_id'
878
879             # Return the newly cached value
880             return self._m2m_reverse_name_cache
881
882     def isValidIDList(self, field_data, all_data):
883         "Validates that the value is a valid list of foreign keys"
884         mod = self.rel.to
885         try:
886             pks = map(int, field_data.split(','))
887         except ValueError:
888             # the CommaSeparatedIntegerField validator will catch this error
889             return
890         objects = mod._default_manager.in_bulk(pks)
891         if len(objects) != len(pks):
892             badkeys = [k for k in pks if k not in objects]
893             raise exceptions.ValidationError(
894                 ungettext("Please enter valid %(self)s IDs. The value %(value)r is invalid.",
895                           "Please enter valid %(self)s IDs. The values %(value)r are invalid.",
896                           len(badkeys)) % {
897                 'self': self.verbose_name,
898                 'value': len(badkeys) == 1 and badkeys[0] or tuple(badkeys),
899             })
900
901     def value_to_string(self, obj):
902         data = ''
903         if obj:
904             qs = getattr(obj, self.name).all()
905             data = [instance._get_pk_val() for instance in qs]
906         else:
907             # In required many-to-many fields with only one available choice,
908             # select that one available choice.
909             if not self.blank:
910                 choices_list = self.get_choices_default()
911                 if len(choices_list) == 1:
912                     data = [choices_list[0][0]]
913         return smart_unicode(data)
914
915     def contribute_to_class(self, cls, name):
916         # To support multiple relations to self, it's useful to have a non-None
917         # related name on symmetrical relations for internal reasons. The
918         # concept doesn't make a lot of sense externally ("you want me to
919         # specify *what* on my non-reversible relation?!"), so we set it up
920         # automatically. The funky name reduces the chance of an accidental
921         # clash.
922         if self.rel.symmetrical and self.rel.to == "self" and self.rel.related_name is None:
923             self.rel.related_name = "%s_rel_+" % name
924
925         super(ManyToManyField, self).contribute_to_class(cls, name)
926         # Add the descriptor for the m2m relation
927         setattr(cls, self.name, ReverseManyRelatedObjectsDescriptor(self))
928
929         # Set up the accessor for the m2m table name for the relation
930         self.m2m_db_table = curry(self._get_m2m_db_table, cls._meta)
931
932         # Populate some necessary rel arguments so that cross-app relations
933         # work correctly.
934         if isinstance(self.rel.through, basestring):
935             def resolve_through_model(field, model, cls):
936                 field.rel.through_model = model
937             add_lazy_relation(cls, self, self.rel.through, resolve_through_model)
938         elif self.rel.through:
939             self.rel.through_model = self.rel.through
940             self.rel.through = self.rel.through._meta.object_name
941
942         if isinstance(self.rel.to, basestring):
943             target = self.rel.to
944         else:
945             target = self.rel.to._meta.db_table
946         cls._meta.duplicate_targets[self.column] = (target, "m2m")
947
948     def contribute_to_related_class(self, cls, related):
949         # m2m relations to self do not have a ManyRelatedObjectsDescriptor,
950         # as it would be redundant - unless the field is non-symmetrical.
951         if related.model != related.parent_model or not self.rel.symmetrical:
952             # Add the descriptor for the m2m relation
953             setattr(cls, related.get_accessor_name(), ManyRelatedObjectsDescriptor(related))
954
955         # Set up the accessors for the column names on the m2m table
956         self.m2m_column_name = curry(self._get_m2m_column_name, related)
957         self.m2m_reverse_name = curry(self._get_m2m_reverse_name, related)
958
959     def set_attributes_from_rel(self):
960         pass
961
962     def value_from_object(self, obj):
963         "Returns the value of this field in the given model instance."
964         return getattr(obj, self.attname).all()
965
966     def save_form_data(self, instance, data):
967         setattr(instance, self.attname, data)
968
969     def formfield(self, **kwargs):
970         defaults = {'form_class': forms.ModelMultipleChoiceField, 'queryset': self.rel.to._default_manager.complex_filter(self.rel.limit_choices_to)}
971         defaults.update(kwargs)
972         # If initial is passed in, it's a list of related objects, but the
973         # MultipleChoiceField takes a list of IDs.
974         if defaults.get('initial') is not None:
975             initial = defaults['initial']
976             if callable(initial):
977                 initial = initial()
978             defaults['initial'] = [i._get_pk_val() for i in initial]
979         return super(ManyToManyField, self).formfield(**defaults)
980
981     def db_type(self):
982         # A ManyToManyField is not represented by a single column,
983         # so return None.
984         return None
Note: See TracBrowser for help on using the browser.