Ticket #10811: related.py

File related.py, 62.7 KB (added by ANUBHAV JOSHI, 10 years ago)
Line 
1from operator import attrgetter
2
3from django.db import connection, connections, router
4from django.db.backends import util
5from django.db.models import signals, get_model
6from django.db.models.fields import (AutoField, Field, IntegerField,
7 PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist)
8from django.db.models.related import RelatedObject
9from django.db.models.query import QuerySet
10from django.db.models.query_utils import QueryWrapper
11from django.db.models.deletion import CASCADE
12from django.utils.encoding import smart_text
13from django.utils import six
14from django.utils.translation import ugettext_lazy as _, string_concat
15from django.utils.functional import curry, cached_property
16from django.core import exceptions
17from django import forms
18
19
20RECURSIVE_RELATIONSHIP_CONSTANT = 'self'
21
22pending_lookups = {}
23
24
25def add_lazy_relation(cls, field, relation, operation):
26 """
27 Adds a lookup on ``cls`` when a related field is defined using a string,
28 i.e.::
29
30 class MyModel(Model):
31 fk = ForeignKey("AnotherModel")
32
33 This string can be:
34
35 * RECURSIVE_RELATIONSHIP_CONSTANT (i.e. "self") to indicate a recursive
36 relation.
37
38 * The name of a model (i.e "AnotherModel") to indicate another model in
39 the same app.
40
41 * An app-label and model name (i.e. "someapp.AnotherModel") to indicate
42 another model in a different app.
43
44 If the other model hasn't yet been loaded -- almost a given if you're using
45 lazy relationships -- then the relation won't be set up until the
46 class_prepared signal fires at the end of model initialization.
47
48 operation is the work that must be performed once the relation can be resolved.
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
58 if isinstance(relation, six.string_types):
59 try:
60 app_label, model_name = relation.split(".")
61 except ValueError:
62 # If we can't split, assume a model in current app
63 app_label = cls._meta.app_label
64 model_name = relation
65 else:
66 # it's actually a model class
67 app_label = relation._meta.app_label
68 model_name = relation._meta.object_name
69
70 # Try to look up the related model, and if it's already loaded resolve the
71 # string right away. If get_model returns None, it means that the related
72 # model isn't loaded yet, so we need to pend the relation until the class
73 # is prepared.
74 model = get_model(app_label, model_name,
75 seed_cache=False, only_installed=False)
76 if model:
77 operation(field, model, cls)
78 else:
79 key = (app_label, model_name)
80 value = (cls, field, operation)
81 pending_lookups.setdefault(key, []).append(value)
82
83
84def do_pending_lookups(sender, **kwargs):
85 """
86 Handle any pending relations to the sending model. Sent from class_prepared.
87 """
88 key = (sender._meta.app_label, sender.__name__)
89 for cls, field, operation in pending_lookups.pop(key, []):
90 operation(field, sender, cls)
91
92signals.class_prepared.connect(do_pending_lookups)
93
94
95#HACK
96class RelatedField(object):
97 def contribute_to_class(self, cls, name):
98 sup = super(RelatedField, self)
99
100 # Store the opts for related_query_name()
101 self.opts = cls._meta
102
103 if hasattr(sup, 'contribute_to_class'):
104 sup.contribute_to_class(cls, name)
105
106 if not cls._meta.abstract and self.rel.related_name:
107 self.rel.related_name = self.rel.related_name % {
108 'class': cls.__name__.lower(),
109 'app_label': cls._meta.app_label.lower(),
110 }
111
112 other = self.rel.to
113 if isinstance(other, six.string_types) or other._meta.pk is None:
114 def resolve_related_class(field, model, cls):
115 field.rel.to = model
116 field.do_related_class(model, cls)
117 add_lazy_relation(cls, self, other, resolve_related_class)
118 else:
119 self.do_related_class(other, cls)
120
121 def set_attributes_from_rel(self):
122 self.name = self.name or (self.rel.to._meta.object_name.lower() + '_' + self.rel.to._meta.pk.name)
123 if self.verbose_name is None:
124 self.verbose_name = self.rel.to._meta.verbose_name
125 self.rel.field_name = self.rel.field_name or self.rel.to._meta.pk.name
126
127 def do_related_class(self, other, cls):
128 self.set_attributes_from_rel()
129 self.related = RelatedObject(other, cls, self)
130 if not cls._meta.abstract:
131 self.contribute_to_related_class(other, self.related)
132
133 def get_prep_lookup(self, lookup_type, value):
134 if hasattr(value, 'prepare'):
135 return value.prepare()
136 if hasattr(value, '_prepare'):
137 return value._prepare()
138 # FIXME: lt and gt are explicitly allowed to make
139 # get_(next/prev)_by_date work; other lookups are not allowed since that
140 # gets messy pretty quick. This is a good candidate for some refactoring
141 # in the future.
142 if lookup_type in ['exact', 'gt', 'lt', 'gte', 'lte']:
143 return self._pk_trace(value, 'get_prep_lookup', lookup_type)
144 if lookup_type in ('range', 'in'):
145 return [self._pk_trace(v, 'get_prep_lookup', lookup_type) for v in value]
146 elif lookup_type == 'isnull':
147 return []
148 raise TypeError("Related Field has invalid lookup: %s" % lookup_type)
149
150 def get_db_prep_lookup(self, lookup_type, value, connection, prepared=False):
151 if not prepared:
152 value = self.get_prep_lookup(lookup_type, value)
153 if hasattr(value, 'get_compiler'):
154 value = value.get_compiler(connection=connection)
155 if hasattr(value, 'as_sql') or hasattr(value, '_as_sql'):
156 # If the value has a relabel_aliases method, it will need to
157 # be invoked before the final SQL is evaluated
158 if hasattr(value, 'relabel_aliases'):
159 return value
160 if hasattr(value, 'as_sql'):
161 sql, params = value.as_sql()
162 else:
163 sql, params = value._as_sql(connection=connection)
164 return QueryWrapper(('(%s)' % sql), params)
165
166 # FIXME: lt and gt are explicitly allowed to make
167 # get_(next/prev)_by_date work; other lookups are not allowed since that
168 # gets messy pretty quick. This is a good candidate for some refactoring
169 # in the future.
170 if lookup_type in ['exact', 'gt', 'lt', 'gte', 'lte']:
171 return [self._pk_trace(value, 'get_db_prep_lookup', lookup_type,
172 connection=connection, prepared=prepared)]
173 if lookup_type in ('range', 'in'):
174 return [self._pk_trace(v, 'get_db_prep_lookup', lookup_type,
175 connection=connection, prepared=prepared)
176 for v in value]
177 elif lookup_type == 'isnull':
178 return []
179 raise TypeError("Related Field has invalid lookup: %s" % lookup_type)
180
181 def _pk_trace(self, value, prep_func, lookup_type, **kwargs):
182 # Value may be a primary key, or an object held in a relation.
183 # If it is an object, then we need to get the primary key value for
184 # that object. In certain conditions (especially one-to-one relations),
185 # the primary key may itself be an object - so we need to keep drilling
186 # down until we hit a value that can be used for a comparison.
187 v = value
188
189 # In the case of an FK to 'self', this check allows to_field to be used
190 # for both forwards and reverse lookups across the FK. (For normal FKs,
191 # it's only relevant for forward lookups).
192 if isinstance(v, self.rel.to):
193 field_name = getattr(self.rel, "field_name", None)
194 else:
195 field_name = None
196 try:
197 while True:
198 if field_name is None:
199 field_name = v._meta.pk.name
200 v = getattr(v, field_name)
201 field_name = None
202 except AttributeError:
203 pass
204 except exceptions.ObjectDoesNotExist:
205 v = None
206
207 field = self
208 while field.rel:
209 if hasattr(field.rel, 'field_name'):
210 field = field.rel.to._meta.get_field(field.rel.field_name)
211 else:
212 field = field.rel.to._meta.pk
213
214 if lookup_type in ('range', 'in'):
215 v = [v]
216 v = getattr(field, prep_func)(lookup_type, v, **kwargs)
217 if isinstance(v, list):
218 v = v[0]
219 return v
220
221 def related_query_name(self):
222 # This method defines the name that can be used to identify this
223 # related object in a table-spanning query. It uses the lower-cased
224 # object_name by default, but this can be overridden with the
225 # "related_name" option.
226 return self.rel.related_name or self.opts.object_name.lower()
227
228
229class SingleRelatedObjectDescriptor(object):
230 # This class provides the functionality that makes the related-object
231 # managers available as attributes on a model class, for fields that have
232 # a single "remote" value, on the class pointed to by a related field.
233 # In the example "place.restaurant", the restaurant attribute is a
234 # SingleRelatedObjectDescriptor instance.
235 def __init__(self, related):
236 self.related = related
237 self.cache_name = related.get_cache_name()
238
239 def is_cached(self, instance):
240 return hasattr(instance, self.cache_name)
241
242 def get_query_set(self, **db_hints):
243 db = router.db_for_read(self.related.model, **db_hints)
244 return self.related.model._base_manager.using(db)
245
246 def get_prefetch_query_set(self, instances):
247 rel_obj_attr = attrgetter(self.related.field.attname)
248 instance_attr = lambda obj: obj._get_pk_val()
249 instances_dict = dict((instance_attr(inst), inst) for inst in instances)
250 params = {'%s__pk__in' % self.related.field.name: list(instances_dict)}
251 qs = self.get_query_set(instance=instances[0]).filter(**params)
252 # Since we're going to assign directly in the cache,
253 # we must manage the reverse relation cache manually.
254 rel_obj_cache_name = self.related.field.get_cache_name()
255 for rel_obj in qs:
256 instance = instances_dict[rel_obj_attr(rel_obj)]
257 setattr(rel_obj, rel_obj_cache_name, instance)
258 return qs, rel_obj_attr, instance_attr, True, self.cache_name
259
260 def __get__(self, instance, instance_type=None):
261 if instance is None:
262 return self
263 try:
264 rel_obj = getattr(instance, self.cache_name)
265 except AttributeError:
266 related_pk = instance._get_pk_val()
267 if related_pk is None:
268 rel_obj = None
269 else:
270 params = {'%s__pk' % self.related.field.name: related_pk}
271 try:
272 rel_obj = self.get_query_set(instance=instance).get(**params)
273 except self.related.model.DoesNotExist:
274 rel_obj = None
275 else:
276 setattr(rel_obj, self.related.field.get_cache_name(), instance)
277 setattr(instance, self.cache_name, rel_obj)
278 if rel_obj is None:
279 raise self.related.model.DoesNotExist
280 else:
281 return rel_obj
282
283 def __set__(self, instance, value):
284 if instance is None:
285 raise AttributeError("%s must be accessed via instance" % self.related.opts.object_name)
286
287 # The similarity of the code below to the code in
288 # ReverseSingleRelatedObjectDescriptor is annoying, but there's a bunch
289 # of small differences that would make a common base class convoluted.
290
291 # If null=True, we can assign null here, but otherwise the value needs
292 # to be an instance of the related class.
293 if value is None and self.related.field.null == False:
294 raise ValueError('Cannot assign None: "%s.%s" does not allow null values.' %
295 (instance._meta.object_name, self.related.get_accessor_name()))
296 elif value is not None and not isinstance(value, self.related.model):
297 raise ValueError('Cannot assign "%r": "%s.%s" must be a "%s" instance.' %
298 (value, instance._meta.object_name,
299 self.related.get_accessor_name(), self.related.opts.object_name))
300 elif value is not None:
301 if instance._state.db is None:
302 instance._state.db = router.db_for_write(instance.__class__, instance=value)
303 elif value._state.db is None:
304 value._state.db = router.db_for_write(value.__class__, instance=instance)
305 elif value._state.db is not None and instance._state.db is not None:
306 if not router.allow_relation(value, instance):
307 raise ValueError('Cannot assign "%r": instance is on database "%s", value is on database "%s"' %
308 (value, instance._state.db, value._state.db))
309
310 related_pk = getattr(instance, self.related.field.rel.get_related_field().attname)
311 if related_pk is None:
312 raise ValueError('Cannot assign "%r": "%s" instance isn\'t saved in the database.' %
313 (value, instance._meta.object_name))
314
315 # Set the value of the related field to the value of the related object's related field
316 setattr(value, self.related.field.attname, related_pk)
317
318 # Since we already know what the related object is, seed the related
319 # object caches now, too. This avoids another db hit if you get the
320 # object you just set.
321 setattr(instance, self.cache_name, value)
322 setattr(value, self.related.field.get_cache_name(), instance)
323
324
325class ReverseSingleRelatedObjectDescriptor(object):
326 # This class provides the functionality that makes the related-object
327 # managers available as attributes on a model class, for fields that have
328 # a single "remote" value, on the class that defines the related field.
329 # In the example "choice.poll", the poll attribute is a
330 # ReverseSingleRelatedObjectDescriptor instance.
331 def __init__(self, field_with_rel):
332 self.field = field_with_rel
333 self.cache_name = self.field.get_cache_name()
334
335 def is_cached(self, instance):
336 return hasattr(instance, self.cache_name)
337
338 def get_query_set(self, **db_hints):
339 db = router.db_for_read(self.field.rel.to, **db_hints)
340 rel_mgr = self.field.rel.to._default_manager
341 # If the related manager indicates that it should be used for
342 # related fields, respect that.
343 if getattr(rel_mgr, 'use_for_related_fields', False):
344 return rel_mgr.using(db)
345 else:
346 return QuerySet(self.field.rel.to).using(db)
347
348 def get_prefetch_query_set(self, instances):
349 other_field = self.field.rel.get_related_field()
350 rel_obj_attr = attrgetter(other_field.attname)
351 instance_attr = attrgetter(self.field.attname)
352 instances_dict = dict((instance_attr(inst), inst) for inst in instances)
353 if other_field.rel:
354 params = {'%s__pk__in' % self.field.rel.field_name: list(instances_dict)}
355 else:
356 params = {'%s__in' % self.field.rel.field_name: list(instances_dict)}
357 qs = self.get_query_set(instance=instances[0]).filter(**params)
358 # Since we're going to assign directly in the cache,
359 # we must manage the reverse relation cache manually.
360 if not self.field.rel.multiple:
361 rel_obj_cache_name = self.field.related.get_cache_name()
362 for rel_obj in qs:
363 instance = instances_dict[rel_obj_attr(rel_obj)]
364 setattr(rel_obj, rel_obj_cache_name, instance)
365 return qs, rel_obj_attr, instance_attr, True, self.cache_name
366
367 def __get__(self, instance, instance_type=None):
368 if instance is None:
369 return self
370 try:
371 rel_obj = getattr(instance, self.cache_name)
372 except AttributeError:
373 val = getattr(instance, self.field.attname)
374 if val is None:
375 rel_obj = None
376 else:
377 other_field = self.field.rel.get_related_field()
378 if other_field.rel:
379 params = {'%s__%s' % (self.field.rel.field_name, other_field.rel.field_name): val}
380 else:
381 params = {'%s__exact' % self.field.rel.field_name: val}
382 qs = self.get_query_set(instance=instance)
383 # Assuming the database enforces foreign keys, this won't fail.
384 rel_obj = qs.get(**params)
385 if not self.field.rel.multiple:
386 setattr(rel_obj, self.field.related.get_cache_name(), instance)
387 setattr(instance, self.cache_name, rel_obj)
388 if rel_obj is None and not self.field.null:
389 raise self.field.rel.to.DoesNotExist
390 else:
391 return rel_obj
392
393 def __set__(self, instance, value):
394 if instance is None:
395 raise AttributeError("%s must be accessed via instance" % self.field.name)
396
397 # If null=True, we can assign null here, but otherwise the value needs
398 # to be an instance of the related class.
399 if value is None and self.field.null == False:
400 raise ValueError('Cannot assign None: "%s.%s" does not allow null values.' %
401 (instance._meta.object_name, self.field.name))
402 elif value is not None and not isinstance(value, self.field.rel.to):
403 raise ValueError('Cannot assign "%r": "%s.%s" must be a "%s" instance.' %
404 (value, instance._meta.object_name,
405 self.field.name, self.field.rel.to._meta.object_name))
406 elif value is not None:
407 if instance._state.db is None:
408 instance._state.db = router.db_for_write(instance.__class__, instance=value)
409 elif value._state.db is None:
410 value._state.db = router.db_for_write(value.__class__, instance=instance)
411 elif value._state.db is not None and instance._state.db is not None:
412 if not router.allow_relation(value, instance):
413 raise ValueError('Cannot assign "%r": instance is on database "%s", value is on database "%s"' %
414 (value, instance._state.db, value._state.db))
415
416 # If we're setting the value of a OneToOneField to None, we need to clear
417 # out the cache on any old related object. Otherwise, deleting the
418 # previously-related object will also cause this object to be deleted,
419 # which is wrong.
420 if value is None:
421 # Look up the previously-related object, which may still be available
422 # since we've not yet cleared out the related field.
423 # Use the cache directly, instead of the accessor; if we haven't
424 # populated the cache, then we don't care - we're only accessing
425 # the object to invalidate the accessor cache, so there's no
426 # need to populate the cache just to expire it again.
427 related = getattr(instance, self.cache_name, None)
428
429 # If we've got an old related object, we need to clear out its
430 # cache. This cache also might not exist if the related object
431 # hasn't been accessed yet.
432 if related is not None:
433 setattr(related, self.field.related.get_cache_name(), None)
434
435 # Set the value of the related field
436 try:
437 val = getattr(value, self.field.rel.get_related_field().attname)
438 if val == None:
439 raise ValueError("The %s does not exists on the database." %value)
440 except AttributeError:
441 val = None
442 setattr(instance, self.field.attname, val)
443
444 # Since we already know what the related object is, seed the related
445 # object caches now, too. This avoids another db hit if you get the
446 # object you just set.
447 setattr(instance, self.cache_name, value)
448 if value is not None and not self.field.rel.multiple:
449 setattr(value, self.field.related.get_cache_name(), instance)
450
451
452class ForeignRelatedObjectsDescriptor(object):
453 # This class provides the functionality that makes the related-object
454 # managers available as attributes on a model class, for fields that have
455 # multiple "remote" values and have a ForeignKey pointed at them by
456 # some other model. In the example "poll.choice_set", the choice_set
457 # attribute is a ForeignRelatedObjectsDescriptor instance.
458 def __init__(self, related):
459 self.related = related # RelatedObject instance
460
461 def __get__(self, instance, instance_type=None):
462 if instance is None:
463 return self
464
465 return self.related_manager_cls(instance)
466
467 def __set__(self, instance, value):
468 if instance is None:
469 raise AttributeError("Manager must be accessed via instance")
470
471 manager = self.__get__(instance)
472 # If the foreign key can support nulls, then completely clear the related set.
473 # Otherwise, just move the named objects into the set.
474 if self.related.field.null:
475 manager.clear()
476 manager.add(*value)
477
478 @cached_property
479 def related_manager_cls(self):
480 # Dynamically create a class that subclasses the related model's default
481 # manager.
482 superclass = self.related.model._default_manager.__class__
483 rel_field = self.related.field
484 rel_model = self.related.model
485 attname = rel_field.rel.get_related_field().attname
486
487 class RelatedManager(superclass):
488 def __init__(self, instance):
489 super(RelatedManager, self).__init__()
490 self.instance = instance
491 self.core_filters = {
492 '%s__%s' % (rel_field.name, attname): getattr(instance, attname)
493 }
494 self.model = rel_model
495
496 def get_query_set(self):
497 try:
498 return self.instance._prefetched_objects_cache[rel_field.related_query_name()]
499 except (AttributeError, KeyError):
500 db = self._db or router.db_for_read(self.model, instance=self.instance)
501 qs = super(RelatedManager, self).get_query_set().using(db).filter(**self.core_filters)
502 val = getattr(self.instance, attname)
503 if val is None or val == '' and connections[db].features.interprets_empty_strings_as_nulls:
504 # We don't want to use qs.none() here, see #19652
505 return qs.filter(pk__in=[])
506 qs._known_related_objects = {rel_field: {self.instance.pk: self.instance}}
507 return qs
508
509 def get_prefetch_query_set(self, instances):
510 rel_obj_attr = attrgetter(rel_field.attname)
511 instance_attr = attrgetter(attname)
512 instances_dict = dict((instance_attr(inst), inst) for inst in instances)
513 db = self._db or router.db_for_read(self.model, instance=instances[0])
514 query = {'%s__%s__in' % (rel_field.name, attname): list(instances_dict)}
515 qs = super(RelatedManager, self).get_query_set().using(db).filter(**query)
516 # Since we just bypassed this class' get_query_set(), we must manage
517 # the reverse relation manually.
518 for rel_obj in qs:
519 instance = instances_dict[rel_obj_attr(rel_obj)]
520 setattr(rel_obj, rel_field.name, instance)
521 cache_name = rel_field.related_query_name()
522 return qs, rel_obj_attr, instance_attr, False, cache_name
523
524 def add(self, *objs):
525 for obj in objs:
526 if not isinstance(obj, self.model):
527 raise TypeError("'%s' instance expected, got %r" % (self.model._meta.object_name, obj))
528 setattr(obj, rel_field.name, self.instance)
529 obj.save()
530 add.alters_data = True
531
532 def create(self, **kwargs):
533 kwargs[rel_field.name] = self.instance
534 db = router.db_for_write(self.model, instance=self.instance)
535 return super(RelatedManager, self.db_manager(db)).create(**kwargs)
536 create.alters_data = True
537
538 def get_or_create(self, **kwargs):
539 # Update kwargs with the related object that this
540 # ForeignRelatedObjectsDescriptor knows about.
541 kwargs[rel_field.name] = self.instance
542 db = router.db_for_write(self.model, instance=self.instance)
543 return super(RelatedManager, self.db_manager(db)).get_or_create(**kwargs)
544 get_or_create.alters_data = True
545
546 # remove() and clear() are only provided if the ForeignKey can have a value of null.
547 if rel_field.null:
548 def remove(self, *objs):
549 val = getattr(self.instance, attname)
550 for obj in objs:
551 # Is obj actually part of this descriptor set?
552 if getattr(obj, rel_field.attname) == val:
553 setattr(obj, rel_field.name, None)
554 obj.save()
555 else:
556 raise rel_field.rel.to.DoesNotExist("%r is not related to %r." % (obj, self.instance))
557 remove.alters_data = True
558
559 def clear(self):
560 self.update(**{rel_field.name: None})
561 clear.alters_data = True
562
563 return RelatedManager
564
565
566def create_many_related_manager(superclass, rel):
567 """Creates a manager that subclasses 'superclass' (which is a Manager)
568 and adds behavior for many-to-many related objects."""
569 class ManyRelatedManager(superclass):
570 def __init__(self, model=None, query_field_name=None, instance=None, symmetrical=None,
571 source_field_name=None, target_field_name=None, reverse=False,
572 through=None, prefetch_cache_name=None):
573 super(ManyRelatedManager, self).__init__()
574 self.model = model
575 self.query_field_name = query_field_name
576 self.core_filters = {'%s__pk' % query_field_name: instance._get_pk_val()}
577 self.instance = instance
578 self.symmetrical = symmetrical
579 self.source_field_name = source_field_name
580 self.target_field_name = target_field_name
581 self.reverse = reverse
582 self.through = through
583 self.prefetch_cache_name = prefetch_cache_name
584 self._fk_val = self._get_fk_val(instance, source_field_name)
585 if self._fk_val is None:
586 raise ValueError('"%r" needs to have a value for field "%s" before '
587 'this many-to-many relationship can be used.' %
588 (instance, source_field_name))
589 # Even if this relation is not to pk, we require still pk value.
590 # The wish is that the instance has been already saved to DB,
591 # although having a pk value isn't a guarantee of that.
592 if instance.pk is None:
593 raise ValueError("%r instance needs to have a primary key value before "
594 "a many-to-many relationship can be used." %
595 instance.__class__.__name__)
596
597 def _get_fk_val(self, obj, field_name):
598 """
599 Returns the correct value for this relationship's foreign key. This
600 might be something else than pk value when to_field is used.
601 """
602 if not self.through:
603 # Make custom m2m fields with no through model defined usable.
604 return obj.pk
605 fk = self.through._meta.get_field(field_name)
606 if fk.rel.field_name and fk.rel.field_name != fk.rel.to._meta.pk.attname:
607 attname = fk.rel.get_related_field().get_attname()
608 return fk.get_prep_lookup('exact', getattr(obj, attname))
609 else:
610 return obj.pk
611
612 def get_query_set(self):
613 try:
614 return self.instance._prefetched_objects_cache[self.prefetch_cache_name]
615 except (AttributeError, KeyError):
616 db = self._db or router.db_for_read(self.instance.__class__, instance=self.instance)
617 return super(ManyRelatedManager, self).get_query_set().using(db)._next_is_sticky().filter(**self.core_filters)
618
619 def get_prefetch_query_set(self, instances):
620 instance = instances[0]
621 from django.db import connections
622 db = self._db or router.db_for_read(instance.__class__, instance=instance)
623 query = {'%s__pk__in' % self.query_field_name:
624 set(obj._get_pk_val() for obj in instances)}
625 qs = super(ManyRelatedManager, self).get_query_set().using(db)._next_is_sticky().filter(**query)
626
627 # M2M: need to annotate the query in order to get the primary model
628 # that the secondary model was actually related to. We know that
629 # there will already be a join on the join table, so we can just add
630 # the select.
631
632 # For non-autocreated 'through' models, can't assume we are
633 # dealing with PK values.
634 fk = self.through._meta.get_field(self.source_field_name)
635 source_col = fk.column
636 join_table = self.through._meta.db_table
637 connection = connections[db]
638 qn = connection.ops.quote_name
639 qs = qs.extra(select={'_prefetch_related_val':
640 '%s.%s' % (qn(join_table), qn(source_col))})
641 select_attname = fk.rel.get_related_field().get_attname()
642 return (qs,
643 attrgetter('_prefetch_related_val'),
644 attrgetter(select_attname),
645 False,
646 self.prefetch_cache_name)
647
648 # If the ManyToMany relation has an intermediary model,
649 # the add and remove methods do not exist.
650 if rel.through._meta.auto_created:
651 def add(self, *objs):
652 self._add_items(self.source_field_name, self.target_field_name, *objs)
653
654 # If this is a symmetrical m2m relation to self, add the mirror entry in the m2m table
655 if self.symmetrical:
656 self._add_items(self.target_field_name, self.source_field_name, *objs)
657 add.alters_data = True
658
659 def remove(self, *objs):
660 self._remove_items(self.source_field_name, self.target_field_name, *objs)
661
662 # If this is a symmetrical m2m relation to self, remove the mirror entry in the m2m table
663 if self.symmetrical:
664 self._remove_items(self.target_field_name, self.source_field_name, *objs)
665 remove.alters_data = True
666
667 def clear(self):
668 self._clear_items(self.source_field_name)
669
670 # If this is a symmetrical m2m relation to self, clear the mirror entry in the m2m table
671 if self.symmetrical:
672 self._clear_items(self.target_field_name)
673 clear.alters_data = True
674
675 def create(self, **kwargs):
676 # This check needs to be done here, since we can't later remove this
677 # from the method lookup table, as we do with add and remove.
678 if not self.through._meta.auto_created:
679 opts = self.through._meta
680 raise AttributeError("Cannot use create() on a ManyToManyField which specifies an intermediary model. Use %s.%s's Manager instead." % (opts.app_label, opts.object_name))
681 db = router.db_for_write(self.instance.__class__, instance=self.instance)
682 new_obj = super(ManyRelatedManager, self.db_manager(db)).create(**kwargs)
683 self.add(new_obj)
684 return new_obj
685 create.alters_data = True
686
687 def get_or_create(self, **kwargs):
688 db = router.db_for_write(self.instance.__class__, instance=self.instance)
689 obj, created = \
690 super(ManyRelatedManager, self.db_manager(db)).get_or_create(**kwargs)
691 # We only need to add() if created because if we got an object back
692 # from get() then the relationship already exists.
693 if created:
694 self.add(obj)
695 return obj, created
696 get_or_create.alters_data = True
697
698 def _add_items(self, source_field_name, target_field_name, *objs):
699 # source_field_name: the PK fieldname in join table for the source object
700 # target_field_name: the PK fieldname in join table for the target object
701 # *objs - objects to add. Either object instances, or primary keys of object instances.
702
703 # If there aren't any objects, there is nothing to do.
704 from django.db.models import Model
705 if objs:
706 new_ids = set()
707 for obj in objs:
708 if isinstance(obj, self.model):
709 if not router.allow_relation(obj, self.instance):
710 raise ValueError('Cannot add "%r": instance is on database "%s", value is on database "%s"' %
711 (obj, self.instance._state.db, obj._state.db))
712 fk_val = self._get_fk_val(obj, target_field_name)
713 if fk_val is None:
714 raise ValueError('Cannot add "%r": the value for field "%s" is None' %
715 (obj, target_field_name))
716 new_ids.add(self._get_fk_val(obj, target_field_name))
717 elif isinstance(obj, Model):
718 raise TypeError("'%s' instance expected, got %r" % (self.model._meta.object_name, obj))
719 else:
720 new_ids.add(obj)
721 db = router.db_for_write(self.through, instance=self.instance)
722 vals = self.through._default_manager.using(db).values_list(target_field_name, flat=True)
723 vals = vals.filter(**{
724 source_field_name: self._fk_val,
725 '%s__in' % target_field_name: new_ids,
726 })
727 new_ids = new_ids - set(vals)
728
729 if self.reverse or source_field_name == self.source_field_name:
730 # Don't send the signal when we are inserting the
731 # duplicate data row for symmetrical reverse entries.
732 signals.m2m_changed.send(sender=self.through, action='pre_add',
733 instance=self.instance, reverse=self.reverse,
734 model=self.model, pk_set=new_ids, using=db)
735 # Add the ones that aren't there already
736 self.through._default_manager.using(db).bulk_create([
737 self.through(**{
738 '%s_id' % source_field_name: self._fk_val,
739 '%s_id' % target_field_name: obj_id,
740 })
741 for obj_id in new_ids
742 ])
743
744 if self.reverse or source_field_name == self.source_field_name:
745 # Don't send the signal when we are inserting the
746 # duplicate data row for symmetrical reverse entries.
747 signals.m2m_changed.send(sender=self.through, action='post_add',
748 instance=self.instance, reverse=self.reverse,
749 model=self.model, pk_set=new_ids, using=db)
750
751 def _remove_items(self, source_field_name, target_field_name, *objs):
752 # source_field_name: the PK colname in join table for the source object
753 # target_field_name: the PK colname in join table for the target object
754 # *objs - objects to remove
755
756 # If there aren't any objects, there is nothing to do.
757 if objs:
758 # Check that all the objects are of the right type
759 old_ids = set()
760 for obj in objs:
761 if isinstance(obj, self.model):
762 old_ids.add(self._get_fk_val(obj, target_field_name))
763 else:
764 old_ids.add(obj)
765 # Work out what DB we're operating on
766 db = router.db_for_write(self.through, instance=self.instance)
767 # Send a signal to the other end if need be.
768 if self.reverse or source_field_name == self.source_field_name:
769 # Don't send the signal when we are deleting the
770 # duplicate data row for symmetrical reverse entries.
771 signals.m2m_changed.send(sender=self.through, action="pre_remove",
772 instance=self.instance, reverse=self.reverse,
773 model=self.model, pk_set=old_ids, using=db)
774 # Remove the specified objects from the join table
775 self.through._default_manager.using(db).filter(**{
776 source_field_name: self._fk_val,
777 '%s__in' % target_field_name: old_ids
778 }).delete()
779 if self.reverse or source_field_name == self.source_field_name:
780 # Don't send the signal when we are deleting the
781 # duplicate data row for symmetrical reverse entries.
782 signals.m2m_changed.send(sender=self.through, action="post_remove",
783 instance=self.instance, reverse=self.reverse,
784 model=self.model, pk_set=old_ids, using=db)
785
786 def _clear_items(self, source_field_name):
787 db = router.db_for_write(self.through, instance=self.instance)
788 # source_field_name: the PK colname in join table for the source object
789 if self.reverse or source_field_name == self.source_field_name:
790 # Don't send the signal when we are clearing the
791 # duplicate data rows for symmetrical reverse entries.
792 signals.m2m_changed.send(sender=self.through, action="pre_clear",
793 instance=self.instance, reverse=self.reverse,
794 model=self.model, pk_set=None, using=db)
795 self.through._default_manager.using(db).filter(**{
796 source_field_name: self._fk_val
797 }).delete()
798 if self.reverse or source_field_name == self.source_field_name:
799 # Don't send the signal when we are clearing the
800 # duplicate data rows for symmetrical reverse entries.
801 signals.m2m_changed.send(sender=self.through, action="post_clear",
802 instance=self.instance, reverse=self.reverse,
803 model=self.model, pk_set=None, using=db)
804
805 return ManyRelatedManager
806
807
808class ManyRelatedObjectsDescriptor(object):
809 # This class provides the functionality that makes the related-object
810 # managers available as attributes on a model class, for fields that have
811 # multiple "remote" values and have a ManyToManyField pointed at them by
812 # some other model (rather than having a ManyToManyField themselves).
813 # In the example "publication.article_set", the article_set attribute is a
814 # ManyRelatedObjectsDescriptor instance.
815 def __init__(self, related):
816 self.related = related # RelatedObject instance
817
818 @cached_property
819 def related_manager_cls(self):
820 # Dynamically create a class that subclasses the related
821 # model's default manager.
822 return create_many_related_manager(
823 self.related.model._default_manager.__class__,
824 self.related.field.rel
825 )
826
827 def __get__(self, instance, instance_type=None):
828 if instance is None:
829 return self
830
831 rel_model = self.related.model
832
833 manager = self.related_manager_cls(
834 model=rel_model,
835 query_field_name=self.related.field.name,
836 prefetch_cache_name=self.related.field.related_query_name(),
837 instance=instance,
838 symmetrical=False,
839 source_field_name=self.related.field.m2m_reverse_field_name(),
840 target_field_name=self.related.field.m2m_field_name(),
841 reverse=True,
842 through=self.related.field.rel.through,
843 )
844
845 return manager
846
847 def __set__(self, instance, value):
848 if instance is None:
849 raise AttributeError("Manager must be accessed via instance")
850
851 if not self.related.field.rel.through._meta.auto_created:
852 opts = self.related.field.rel.through._meta
853 raise AttributeError("Cannot set values on a ManyToManyField which specifies an intermediary model. Use %s.%s's Manager instead." % (opts.app_label, opts.object_name))
854
855 manager = self.__get__(instance)
856 manager.clear()
857 manager.add(*value)
858
859
860class ReverseManyRelatedObjectsDescriptor(object):
861 # This class provides the functionality that makes the related-object
862 # managers available as attributes on a model class, for fields that have
863 # multiple "remote" values and have a ManyToManyField defined in their
864 # model (rather than having another model pointed *at* them).
865 # In the example "article.publications", the publications attribute is a
866 # ReverseManyRelatedObjectsDescriptor instance.
867 def __init__(self, m2m_field):
868 self.field = m2m_field
869
870 @property
871 def through(self):
872 # through is provided so that you have easy access to the through
873 # model (Book.authors.through) for inlines, etc. This is done as
874 # a property to ensure that the fully resolved value is returned.
875 return self.field.rel.through
876
877 @cached_property
878 def related_manager_cls(self):
879 # Dynamically create a class that subclasses the related model's
880 # default manager.
881 return create_many_related_manager(
882 self.field.rel.to._default_manager.__class__,
883 self.field.rel
884 )
885
886 def __get__(self, instance, instance_type=None):
887 if instance is None:
888 return self
889
890 manager = self.related_manager_cls(
891 model=self.field.rel.to,
892 query_field_name=self.field.related_query_name(),
893 prefetch_cache_name=self.field.name,
894 instance=instance,
895 symmetrical=self.field.rel.symmetrical,
896 source_field_name=self.field.m2m_field_name(),
897 target_field_name=self.field.m2m_reverse_field_name(),
898 reverse=False,
899 through=self.field.rel.through,
900 )
901
902 return manager
903
904 def __set__(self, instance, value):
905 if instance is None:
906 raise AttributeError("Manager must be accessed via instance")
907
908 if not self.field.rel.through._meta.auto_created:
909 opts = self.field.rel.through._meta
910 raise AttributeError("Cannot set values on a ManyToManyField which specifies an intermediary model. Use %s.%s's Manager instead." % (opts.app_label, opts.object_name))
911
912 manager = self.__get__(instance)
913 manager.clear()
914 manager.add(*value)
915
916
917class ManyToOneRel(object):
918 def __init__(self, to, field_name, related_name=None, limit_choices_to=None,
919 parent_link=False, on_delete=None):
920 try:
921 to._meta
922 except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
923 assert isinstance(to, six.string_types), "'to' must be either a model, a model name or the string %r" % RECURSIVE_RELATIONSHIP_CONSTANT
924 self.to, self.field_name = to, field_name
925 self.related_name = related_name
926 if limit_choices_to is None:
927 limit_choices_to = {}
928 self.limit_choices_to = limit_choices_to
929 self.multiple = True
930 self.parent_link = parent_link
931 self.on_delete = on_delete
932
933 def is_hidden(self):
934 "Should the related object be hidden?"
935 return self.related_name and self.related_name[-1] == '+'
936
937 def get_related_field(self):
938 """
939 Returns the Field in the 'to' object to which this relationship is
940 tied.
941 """
942 data = self.to._meta.get_field_by_name(self.field_name)
943 if not data[2]:
944 raise FieldDoesNotExist("No related field named '%s'" %
945 self.field_name)
946 return data[0]
947
948
949class OneToOneRel(ManyToOneRel):
950 def __init__(self, to, field_name, related_name=None, limit_choices_to=None,
951 parent_link=False, on_delete=None):
952 super(OneToOneRel, self).__init__(to, field_name,
953 related_name=related_name, limit_choices_to=limit_choices_to,
954 parent_link=parent_link, on_delete=on_delete
955 )
956 self.multiple = False
957
958
959class ManyToManyRel(object):
960 def __init__(self, to, related_name=None, limit_choices_to=None,
961 symmetrical=True, through=None):
962 self.to = to
963 self.related_name = related_name
964 if limit_choices_to is None:
965 limit_choices_to = {}
966 self.limit_choices_to = limit_choices_to
967 self.symmetrical = symmetrical
968 self.multiple = True
969 self.through = through
970
971 def is_hidden(self):
972 "Should the related object be hidden?"
973 return self.related_name and self.related_name[-1] == '+'
974
975 def get_related_field(self):
976 """
977 Returns the field in the to' object to which this relationship is tied
978 (this is always the primary key on the target model). Provided for
979 symmetry with ManyToOneRel.
980 """
981 return self.to._meta.pk
982
983
984class ForeignKey(RelatedField, Field):
985 empty_strings_allowed = False
986 default_error_messages = {
987 'invalid': _('Model %(model)s with pk %(pk)r does not exist.')
988 }
989 description = _("Foreign Key (type determined by related field)")
990
991 def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs):
992 try:
993 to_name =to._meta.object_name.lower()
994 except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
995 assert isinstance(to, six.string_types), "%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)
996 else:
997 assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name)
998 # For backwards compatibility purposes, we need to *try* and set
999 # the to_field during FK construction. It won't be guaranteed to
1000 # be correct until contribute_to_class is called. Refs #12190.
1001 to_field =to_field or (to._meta.pk and to._meta.pk.name)
1002 kwargs['verbose_name'] = kwargs.get('verbose_name', None)
1003
1004 if 'db_index' not in kwargs:
1005 kwargs['db_index'] = True
1006
1007 kwargs['rel'] = rel_class(to, to_field,
1008 related_name=kwargs.pop('related_name', None),
1009 limit_choices_to=kwargs.pop('limit_choices_to', None),
1010 parent_link=kwargs.pop('parent_link', False),
1011 on_delete=kwargs.pop('on_delete', CASCADE),
1012 )
1013 Field.__init__(self, **kwargs)
1014
1015 def validate(self, value, model_instance):
1016 if self.rel.parent_link:
1017 return
1018 super(ForeignKey, self).validate(value, model_instance)
1019 if value is None:
1020 return
1021
1022 using = router.db_for_read(model_instance.__class__, instance=model_instance)
1023 qs = self.rel.to._default_manager.using(using).filter(
1024 **{self.rel.field_name: value}
1025 )
1026 qs = qs.complex_filter(self.rel.limit_choices_to)
1027 if not qs.exists():
1028 raise exceptions.ValidationError(self.error_messages['invalid'] % {
1029 'model': self.rel.to._meta.verbose_name, 'pk': value})
1030
1031 def get_attname(self):
1032 return '%s_id' % self.name
1033
1034 def get_validator_unique_lookup_type(self):
1035 return '%s__%s__exact' % (self.name, self.rel.get_related_field().name)
1036
1037 def get_default(self):
1038 "Here we check if the default value is an object and return the to_field if so."
1039 field_default = super(ForeignKey, self).get_default()
1040 if isinstance(field_default, self.rel.to):
1041 return getattr(field_default, self.rel.get_related_field().attname)
1042 return field_default
1043
1044 def get_db_prep_save(self, value, connection):
1045 if value == '' or value == None:
1046 return None
1047 else:
1048 return self.rel.get_related_field().get_db_prep_save(value,
1049 connection=connection)
1050
1051 def value_to_string(self, obj):
1052 if not obj:
1053 # In required many-to-one fields with only one available choice,
1054 # select that one available choice. Note: For SelectFields
1055 # we have to check that the length of choices is *2*, not 1,
1056 # because SelectFields always have an initial "blank" value.
1057 if not self.blank and self.choices:
1058 choice_list = self.get_choices_default()
1059 if len(choice_list) == 2:
1060 return smart_text(choice_list[1][0])
1061 return Field.value_to_string(self, obj)
1062
1063 def contribute_to_class(self, cls, name):
1064 super(ForeignKey, self).contribute_to_class(cls, name)
1065 setattr(cls, self.name, ReverseSingleRelatedObjectDescriptor(self))
1066 if isinstance(self.rel.to, six.string_types):
1067 target = self.rel.to
1068 else:
1069 target = self.rel.to._meta.db_table
1070 cls._meta.duplicate_targets[self.column] = (target, "o2m")
1071
1072 def contribute_to_related_class(self, cls, related):
1073 # Internal FK's - i.e., those with a related name ending with '+' -
1074 # and swapped models don't get a related descriptor.
1075 if not self.rel.is_hidden() and not related.model._meta.swapped:
1076 setattr(cls, related.get_accessor_name(), ForeignRelatedObjectsDescriptor(related))
1077 if self.rel.limit_choices_to:
1078 cls._meta.related_fkey_lookups.append(self.rel.limit_choices_to)
1079 if self.rel.field_name is None:
1080 self.rel.field_name = cls._meta.pk.name
1081
1082 def formfield(self, **kwargs):
1083 db = kwargs.pop('using', None)
1084 if isinstance(self.rel.to, six.string_types):
1085 raise ValueError("Cannot create form field for %r yet, because "
1086 "its related model %r has not been loaded yet" %
1087 (self.name, self.rel.to))
1088 defaults = {
1089 'form_class': forms.ModelChoiceField,
1090 'queryset': self.rel.to._default_manager.using(db).complex_filter(self.rel.limit_choices_to),
1091 'to_field_name': self.rel.field_name,
1092 }
1093 defaults.update(kwargs)
1094 return super(ForeignKey, self).formfield(**defaults)
1095
1096 def db_type(self, connection):
1097 # The database column type of a ForeignKey is the column type
1098 # of the field to which it points. An exception is if the ForeignKey
1099 # points to an AutoField/PositiveIntegerField/PositiveSmallIntegerField,
1100 # in which case the column type is simply that of an IntegerField.
1101 # If the database needs similar types for key fields however, the only
1102 # thing we can do is making AutoField an IntegerField.
1103 rel_field = self.rel.get_related_field()
1104 if (isinstance(rel_field, AutoField) or
1105 (not connection.features.related_fields_match_type and
1106 isinstance(rel_field, (PositiveIntegerField,
1107 PositiveSmallIntegerField)))):
1108 return IntegerField().db_type(connection=connection)
1109 return rel_field.db_type(connection=connection)
1110
1111
1112class OneToOneField(ForeignKey):
1113 """
1114 A OneToOneField is essentially the same as a ForeignKey, with the exception
1115 that always carries a "unique" constraint with it and the reverse relation
1116 always returns the object pointed to (since there will only ever be one),
1117 rather than returning a list.
1118 """
1119 description = _("One-to-one relationship")
1120
1121 def __init__(self, to, to_field=None, **kwargs):
1122 kwargs['unique'] = True
1123 super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs)
1124
1125 def contribute_to_related_class(self, cls, related):
1126 setattr(cls, related.get_accessor_name(),
1127 SingleRelatedObjectDescriptor(related))
1128
1129 def formfield(self, **kwargs):
1130 if self.rel.parent_link:
1131 return None
1132 return super(OneToOneField, self).formfield(**kwargs)
1133
1134 def save_form_data(self, instance, data):
1135 if isinstance(data, self.rel.to):
1136 setattr(instance, self.name, data)
1137 else:
1138 setattr(instance, self.attname, data)
1139
1140
1141def create_many_to_many_intermediary_model(field, klass):
1142 from django.db import models
1143 managed = True
1144 if isinstance(field.rel.to, six.string_types) and field.rel.to != RECURSIVE_RELATIONSHIP_CONSTANT:
1145 to_model = field.rel.to
1146 to = to_model.split('.')[-1]
1147
1148 def set_managed(field, model, cls):
1149 field.rel.through._meta.managed = model._meta.managed or cls._meta.managed
1150 add_lazy_relation(klass, field, to_model, set_managed)
1151 elif isinstance(field.rel.to, six.string_types):
1152 to = klass._meta.object_name
1153 to_model = klass
1154 managed = klass._meta.managed
1155 else:
1156 to = field.rel.to._meta.object_name
1157 to_model = field.rel.to
1158 managed = klass._meta.managed or to_model._meta.managed
1159 name = '%s_%s' % (klass._meta.object_name, field.name)
1160 if field.rel.to == RECURSIVE_RELATIONSHIP_CONSTANT or to == klass._meta.object_name:
1161 from_ = 'from_%s' % to.lower()
1162 to = 'to_%s' % to.lower()
1163 else:
1164 from_ = klass._meta.object_name.lower()
1165 to = to.lower()
1166 meta = type('Meta', (object,), {
1167 'db_table': field._get_m2m_db_table(klass._meta),
1168 'managed': managed,
1169 'auto_created': klass,
1170 'app_label': klass._meta.app_label,
1171 'db_tablespace': klass._meta.db_tablespace,
1172 'unique_together': (from_, to),
1173 'verbose_name': '%(from)s-%(to)s relationship' % {'from': from_, 'to': to},
1174 'verbose_name_plural': '%(from)s-%(to)s relationships' % {'from': from_, 'to': to},
1175 })
1176 # Construct and return the new class.
1177 return type(str(name), (models.Model,), {
1178 'Meta': meta,
1179 '__module__': klass.__module__,
1180 from_: models.ForeignKey(klass, related_name='%s+' % name, db_tablespace=field.db_tablespace),
1181 to: models.ForeignKey(to_model, related_name='%s+' % name, db_tablespace=field.db_tablespace)
1182 })
1183
1184
1185class ManyToManyField(RelatedField, Field):
1186 description = _("Many-to-many relationship")
1187
1188 def __init__(self, to, **kwargs):
1189 try:
1190 assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name)
1191 except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
1192 assert isinstance(to, six.string_types), "%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)
1193 # Python 2.6 and earlier require dictionary keys to be of str type,
1194 # not unicode and class names must be ASCII (in Python 2.x), so we
1195 # forcibly coerce it here (breaks early if there's a problem).
1196 to = str(to)
1197
1198 kwargs['verbose_name'] = kwargs.get('verbose_name', None)
1199 kwargs['rel'] = ManyToManyRel(to,
1200 related_name=kwargs.pop('related_name', None),
1201 limit_choices_to=kwargs.pop('limit_choices_to', None),
1202 symmetrical=kwargs.pop('symmetrical', to == RECURSIVE_RELATIONSHIP_CONSTANT),
1203 through=kwargs.pop('through', None))
1204
1205 self.db_table = kwargs.pop('db_table', None)
1206 if kwargs['rel'].through is not None:
1207 assert self.db_table is None, "Cannot specify a db_table if an intermediary model is used."
1208
1209 Field.__init__(self, **kwargs)
1210
1211 msg = _('Hold down "Control", or "Command" on a Mac, to select more than one.')
1212 self.help_text = string_concat(self.help_text, ' ', msg)
1213
1214 def get_choices_default(self):
1215 return Field.get_choices(self, include_blank=False)
1216
1217 def _get_m2m_db_table(self, opts):
1218 "Function that can be curried to provide the m2m table name for this relation"
1219 if self.rel.through is not None:
1220 return self.rel.through._meta.db_table
1221 elif self.db_table:
1222 return self.db_table
1223 else:
1224 return util.truncate_name('%s_%s' % (opts.db_table, self.name),
1225 connection.ops.max_name_length())
1226
1227 def _get_m2m_attr(self, related, attr):
1228 "Function that can be curried to provide the source accessor or DB column name for the m2m table"
1229 cache_attr = '_m2m_%s_cache' % attr
1230 if hasattr(self, cache_attr):
1231 return getattr(self, cache_attr)
1232 for f in self.rel.through._meta.fields:
1233 if hasattr(f, 'rel') and f.rel and f.rel.to == related.model:
1234 setattr(self, cache_attr, getattr(f, attr))
1235 return getattr(self, cache_attr)
1236
1237 def _get_m2m_reverse_attr(self, related, attr):
1238 "Function that can be curried to provide the related accessor or DB column name for the m2m table"
1239 cache_attr = '_m2m_reverse_%s_cache' % attr
1240 if hasattr(self, cache_attr):
1241 return getattr(self, cache_attr)
1242 found = False
1243 for f in self.rel.through._meta.fields:
1244 if hasattr(f, 'rel') and f.rel and f.rel.to == related.parent_model:
1245 if related.model == related.parent_model:
1246 # If this is an m2m-intermediate to self,
1247 # the first foreign key you find will be
1248 # the source column. Keep searching for
1249 # the second foreign key.
1250 if found:
1251 setattr(self, cache_attr, getattr(f, attr))
1252 break
1253 else:
1254 found = True
1255 else:
1256 setattr(self, cache_attr, getattr(f, attr))
1257 break
1258 return getattr(self, cache_attr)
1259
1260 def value_to_string(self, obj):
1261 data = ''
1262 if obj:
1263 qs = getattr(obj, self.name).all()
1264 data = [instance._get_pk_val() for instance in qs]
1265 else:
1266 # In required many-to-many fields with only one available choice,
1267 # select that one available choice.
1268 if not self.blank:
1269 choices_list = self.get_choices_default()
1270 if len(choices_list) == 1:
1271 data = [choices_list[0][0]]
1272 return smart_text(data)
1273
1274 def contribute_to_class(self, cls, name):
1275 # To support multiple relations to self, it's useful to have a non-None
1276 # related name on symmetrical relations for internal reasons. The
1277 # concept doesn't make a lot of sense externally ("you want me to
1278 # specify *what* on my non-reversible relation?!"), so we set it up
1279 # automatically. The funky name reduces the chance of an accidental
1280 # clash.
1281 if self.rel.symmetrical and (self.rel.to == "self" or self.rel.to == cls._meta.object_name):
1282 self.rel.related_name = "%s_rel_+" % name
1283
1284 super(ManyToManyField, self).contribute_to_class(cls, name)
1285
1286 # The intermediate m2m model is not auto created if:
1287 # 1) There is a manually specified intermediate, or
1288 # 2) The class owning the m2m field is abstract.
1289 # 3) The class owning the m2m field has been swapped out.
1290 if not self.rel.through and not cls._meta.abstract and not cls._meta.swapped:
1291 self.rel.through = create_many_to_many_intermediary_model(self, cls)
1292
1293 # Add the descriptor for the m2m relation
1294 setattr(cls, self.name, ReverseManyRelatedObjectsDescriptor(self))
1295
1296 # Set up the accessor for the m2m table name for the relation
1297 self.m2m_db_table = curry(self._get_m2m_db_table, cls._meta)
1298
1299 # Populate some necessary rel arguments so that cross-app relations
1300 # work correctly.
1301 if isinstance(self.rel.through, six.string_types):
1302 def resolve_through_model(field, model, cls):
1303 field.rel.through = model
1304 add_lazy_relation(cls, self, self.rel.through, resolve_through_model)
1305
1306 if isinstance(self.rel.to, six.string_types):
1307 target = self.rel.to
1308 else:
1309 target = self.rel.to._meta.db_table
1310 cls._meta.duplicate_targets[self.column] = (target, "m2m")
1311
1312 def contribute_to_related_class(self, cls, related):
1313 # Internal M2Ms (i.e., those with a related name ending with '+')
1314 # and swapped models don't get a related descriptor.
1315 if not self.rel.is_hidden() and not related.model._meta.swapped:
1316 setattr(cls, related.get_accessor_name(), ManyRelatedObjectsDescriptor(related))
1317
1318 # Set up the accessors for the column names on the m2m table
1319 self.m2m_column_name = curry(self._get_m2m_attr, related, 'column')
1320 self.m2m_reverse_name = curry(self._get_m2m_reverse_attr, related, 'column')
1321
1322 self.m2m_field_name = curry(self._get_m2m_attr, related, 'name')
1323 self.m2m_reverse_field_name = curry(self._get_m2m_reverse_attr, related, 'name')
1324
1325 get_m2m_rel = curry(self._get_m2m_attr, related, 'rel')
1326 self.m2m_target_field_name = lambda: get_m2m_rel().field_name
1327 get_m2m_reverse_rel = curry(self._get_m2m_reverse_attr, related, 'rel')
1328 self.m2m_reverse_target_field_name = lambda: get_m2m_reverse_rel().field_name
1329
1330 def set_attributes_from_rel(self):
1331 pass
1332
1333 def value_from_object(self, obj):
1334 "Returns the value of this field in the given model instance."
1335 return getattr(obj, self.attname).all()
1336
1337 def save_form_data(self, instance, data):
1338 setattr(instance, self.attname, data)
1339
1340 def formfield(self, **kwargs):
1341 db = kwargs.pop('using', None)
1342 defaults = {
1343 'form_class': forms.ModelMultipleChoiceField,
1344 'queryset': self.rel.to._default_manager.using(db).complex_filter(self.rel.limit_choices_to)
1345 }
1346 defaults.update(kwargs)
1347 # If initial is passed in, it's a list of related objects, but the
1348 # MultipleChoiceField takes a list of IDs.
1349 if defaults.get('initial') is not None:
1350 initial = defaults['initial']
1351 if callable(initial):
1352 initial = initial()
1353 defaults['initial'] = [i._get_pk_val() for i in initial]
1354 return super(ManyToManyField, self).formfield(**defaults)
1355
1356 def db_type(self, connection):
1357 # A ManyToManyField is not represented by a single column,
1358 # so return None.
1359 return None
Back to Top