Loading django/contrib/admin/filters.py +4 −4 Original line number Diff line number Diff line Loading @@ -8,7 +8,7 @@ certain test -- e.g. being a DateField or ForeignKey. import datetime from django.db import models from django.db.models.fields.related import ManyToManyField from django.db.models.fields.related import ForeignObjectRel, ManyToManyField from django.core.exceptions import ImproperlyConfigured, ValidationError from django.utils.encoding import smart_text, force_text from django.utils.translation import ugettext_lazy as _ Loading Loading @@ -180,7 +180,7 @@ class RelatedFieldListFilter(FieldListFilter): self.title = self.lookup_title def has_output(self): if (isinstance(self.field, models.related.RelatedObject) and if (isinstance(self.field, ForeignObjectRel) and self.field.field.null or hasattr(self.field, 'rel') and self.field.null): extra = 1 Loading Loading @@ -210,7 +210,7 @@ class RelatedFieldListFilter(FieldListFilter): }, [self.lookup_kwarg_isnull]), 'display': val, } if (isinstance(self.field, models.related.RelatedObject) and if (isinstance(self.field, ForeignObjectRel) and (self.field.field.null or isinstance(self.field.field, ManyToManyField)) or hasattr(self.field, 'rel') and (self.field.null or isinstance(self.field, ManyToManyField))): yield { Loading @@ -223,7 +223,7 @@ class RelatedFieldListFilter(FieldListFilter): FieldListFilter.register(lambda f: ( bool(f.rel) if hasattr(f, 'rel') else isinstance(f, models.related.RelatedObject)), RelatedFieldListFilter) isinstance(f, ForeignObjectRel)), RelatedFieldListFilter) class BooleanFieldListFilter(FieldListFilter): Loading django/contrib/admin/options.py +2 −2 Original line number Diff line number Diff line Loading @@ -25,8 +25,8 @@ from django.core.paginator import Paginator from django.core.urlresolvers import reverse from django.db import models, transaction, router from django.db.models.constants import LOOKUP_SEP from django.db.models.related import RelatedObject from django.db.models.fields import BLANK_CHOICE_DASH, FieldDoesNotExist from django.db.models.fields.related import ForeignObjectRel from django.db.models.sql.constants import QUERY_TERMS from django.forms.formsets import all_valid, DELETION_FIELD_NAME from django.forms.models import (modelform_factory, modelformset_factory, Loading Loading @@ -421,7 +421,7 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)): rel_name = field.rel.get_related_field().name else: rel_name = None elif isinstance(field, RelatedObject): elif isinstance(field, ForeignObjectRel): model = field.model rel_name = model._meta.pk.name else: Loading django/contrib/admin/utils.py +1 −1 Original line number Diff line number Diff line Loading @@ -304,7 +304,7 @@ def label_for_field(name, model, model_admin=None, return_attr=False): try: label = field.verbose_name except AttributeError: # field is likely a RelatedObject # field is likely a ForeignObjectRel label = field.opts.verbose_name except models.FieldDoesNotExist: if name == "__unicode__": Loading django/contrib/contenttypes/fields.py +2 −1 Original line number Diff line number Diff line Loading @@ -9,7 +9,7 @@ from django.db import models, router, transaction, DEFAULT_DB_ALIAS from django.db.models import signals, FieldDoesNotExist, DO_NOTHING from django.db.models.base import ModelBase from django.db.models.fields.related import ForeignObject, ForeignObjectRel from django.db.models.related import PathInfo from django.db.models.query_utils import PathInfo from django.db.models.expressions import Col from django.contrib.contenttypes.models import ContentType from django.utils.encoding import smart_text, python_2_unicode_compatible Loading @@ -27,6 +27,7 @@ class GenericForeignKey(object): self.fk_field = fk_field self.for_concrete_model = for_concrete_model self.editable = False self.rel = None def contribute_to_class(self, cls, name, **kwargs): self.name = name Loading django/db/models/fields/related.py +106 −32 Original line number Diff line number Diff line from __future__ import unicode_literals from operator import attrgetter import warnings from django.apps import apps from django.core import checks Loading @@ -9,13 +10,15 @@ from django.db.backends import utils from django.db.models import signals, Q from django.db.models.deletion import SET_NULL, SET_DEFAULT, CASCADE from django.db.models.fields import (AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist) PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist, BLANK_CHOICE_DASH) from django.db.models.lookups import IsNull from django.db.models.related import RelatedObject, PathInfo from django.db.models.query import QuerySet from django.db.models.query_utils import PathInfo from django.db.models.expressions import Col from django.utils.encoding import force_text, smart_text from django.utils import six from django.utils.deprecation import RemovedInDjango20Warning from django.utils.translation import ugettext_lazy as _ from django.utils.functional import curry, cached_property from django.core import exceptions Loading Loading @@ -178,7 +181,7 @@ class RelatedField(Field): return [] try: self.related self.rel except AttributeError: return [] Loading @@ -195,7 +198,7 @@ class RelatedField(Field): rel_opts = self.rel.to._meta # rel_opts.object_name == "Target" rel_name = self.related.get_accessor_name() # i. e. "model_set" rel_name = self.rel.get_accessor_name() # i. e. "model_set" rel_query_name = self.related_query_name() # i. e. "model" field_name = "%s.%s" % (opts.object_name, self.name) # i. e. "Model.field" Loading Loading @@ -324,11 +327,17 @@ class RelatedField(Field): self.verbose_name = self.rel.to._meta.verbose_name self.rel.set_field_name() @property def related(self): warnings.warn( "Usage of field.related has been deprecated. Use field.rel instead.", RemovedInDjango20Warning, 2) return self.rel def do_related_class(self, other, cls): self.set_attributes_from_rel() self.related = RelatedObject(other, cls, self) if not cls._meta.abstract: self.contribute_to_related_class(other, self.related) self.contribute_to_related_class(other, self.rel) def get_limit_choices_to(self): """Returns 'limit_choices_to' for this model field. Loading Loading @@ -554,7 +563,7 @@ class ReverseSingleRelatedObjectDescriptor(object): # Since we're going to assign directly in the cache, # we must manage the reverse relation cache manually. if not self.field.rel.multiple: rel_obj_cache_name = self.field.related.get_cache_name() rel_obj_cache_name = self.field.rel.get_cache_name() for rel_obj in queryset: instance = instances_dict[rel_obj_attr(rel_obj)] setattr(rel_obj, rel_obj_cache_name, instance) Loading Loading @@ -583,7 +592,7 @@ class ReverseSingleRelatedObjectDescriptor(object): # Assuming the database enforces foreign keys, this won't fail. rel_obj = qs.get() if not self.field.rel.multiple: setattr(rel_obj, self.field.related.get_cache_name(), instance) setattr(rel_obj, self.field.rel.get_cache_name(), instance) setattr(instance, self.cache_name, rel_obj) if rel_obj is None and not self.field.null: raise self.RelatedObjectDoesNotExist( Loading Loading @@ -635,7 +644,7 @@ class ReverseSingleRelatedObjectDescriptor(object): # cache. This cache also might not exist if the related object # hasn't been accessed yet. if related is not None: setattr(related, self.field.related.get_cache_name(), None) setattr(related, self.field.rel.get_cache_name(), None) for lh_field, rh_field in self.field.related_fields: setattr(instance, lh_field.attname, None) Loading @@ -656,7 +665,7 @@ class ReverseSingleRelatedObjectDescriptor(object): # object you just set. setattr(instance, self.cache_name, value) if value is not None and not self.field.rel.multiple: setattr(value, self.field.related.get_cache_name(), instance) setattr(value, self.field.rel.get_cache_name(), instance) def create_foreign_related_manager(superclass, rel_field, rel_model): Loading Loading @@ -1248,13 +1257,6 @@ class ReverseManyRelatedObjectsDescriptor(object): class ForeignObjectRel(object): def __init__(self, field, to, related_name=None, limit_choices_to=None, parent_link=False, on_delete=None, related_query_name=None): try: to._meta except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT assert isinstance(to, six.string_types), ( "'to' must be either a model, a model name or the string %r" % RECURSIVE_RELATIONSHIP_CONSTANT ) self.field = field self.to = to self.related_name = related_name Loading @@ -1263,6 +1265,56 @@ class ForeignObjectRel(object): self.multiple = True self.parent_link = parent_link self.on_delete = on_delete self.symmetrical = False # This and the following cached_properties can't be initialized in # __init__ as the field doesn't have its model yet. Calling these methods # before field.contribute_to_class() has been called will result in # AttributeError @cached_property def model(self): if not self.field.model: raise AttributeError( "This property can't be accessed before self.field.contribute_to_class has been called.") return self.field.model @cached_property def opts(self): return self.model._meta @cached_property def to_opts(self): return self.to._meta @cached_property def parent_model(self): return self.to @cached_property def name(self): return '%s.%s' % (self.opts.app_label, self.opts.model_name) def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH, limit_to_currently_related=False): """ Returns choices with a default blank choices included, for use as SelectField choices for this field. Analog of django.db.models.fields.Field.get_choices(), provided initially for utilization by RelatedFieldListFilter. """ first_choice = blank_choice if include_blank else [] queryset = self.model._default_manager.all() if limit_to_currently_related: queryset = queryset.complex_filter( {'%s__isnull' % self.parent_model._meta.model_name: False} ) lst = [(x._get_pk_val(), smart_text(x)) for x in queryset] return first_choice + lst def get_db_prep_lookup(self, lookup_type, value, connection, prepared=False): # Defer to the actual field definition for db prep return self.field.get_db_prep_lookup(lookup_type, value, connection=connection, prepared=prepared) def is_hidden(self): "Should the related object be hidden?" Loading @@ -1289,6 +1341,34 @@ class ForeignObjectRel(object): return self.field.get_lookup_constraint(constraint_class, alias, targets, sources, lookup_type, raw_value) def get_accessor_name(self, model=None): # This method encapsulates the logic that decides what name to give an # accessor descriptor that retrieves related many-to-one or # many-to-many objects. It uses the lower-cased object_name + "_set", # but this can be overridden with the "related_name" option. # Due to backwards compatibility ModelForms need to be able to provide # an alternate model. See BaseInlineFormSet.get_default_prefix(). opts = model._meta if model else self.opts model = model or self.model if self.multiple: # If this is a symmetrical m2m relation on self, there is no reverse accessor. if self.symmetrical and model == self.to: return None if self.related_name: return self.related_name if opts.default_related_name: return self.opts.default_related_name % { 'model_name': self.opts.model_name.lower(), 'app_label': self.opts.app_label.lower(), } return opts.model_name + ('_set' if self.multiple else '') def get_cache_name(self): return "_%s_cache" % self.get_accessor_name() def get_path_info(self): return self.field.get_reverse_path_info() class ManyToOneRel(ForeignObjectRel): def __init__(self, field, to, field_name, related_name=None, limit_choices_to=None, Loading Loading @@ -1322,30 +1402,23 @@ class OneToOneRel(ManyToOneRel): self.multiple = False class ManyToManyRel(object): def __init__(self, to, related_name=None, limit_choices_to=None, class ManyToManyRel(ForeignObjectRel): def __init__(self, field, to, related_name=None, limit_choices_to=None, symmetrical=True, through=None, through_fields=None, db_constraint=True, related_query_name=None): if through and not db_constraint: raise ValueError("Can't supply a through model and db_constraint=False") if through_fields and not through: raise ValueError("Cannot specify through_fields without a through model") self.to = to self.related_name = related_name self.related_query_name = related_query_name if limit_choices_to is None: limit_choices_to = {} self.limit_choices_to = limit_choices_to super(ManyToManyRel, self).__init__( field, to, related_name=related_name, limit_choices_to=limit_choices_to, related_query_name=related_query_name) self.symmetrical = symmetrical self.multiple = True self.through = through self.through_fields = through_fields self.db_constraint = db_constraint def is_hidden(self): "Should the related object be hidden?" return self.related_name and self.related_name[-1] == '+' def get_related_field(self): """ Returns the field in the 'to' object to which this relationship is tied. Loading Loading @@ -1402,7 +1475,7 @@ class ForeignObject(RelatedField): return [] try: self.related self.rel except AttributeError: return [] Loading Loading @@ -1979,7 +2052,8 @@ class ManyToManyField(RelatedField): to = str(to) kwargs['verbose_name'] = kwargs.get('verbose_name', None) kwargs['rel'] = ManyToManyRel(to, kwargs['rel'] = ManyToManyRel( self, to, related_name=kwargs.pop('related_name', None), related_query_name=kwargs.pop('related_query_name', None), limit_choices_to=kwargs.pop('limit_choices_to', None), Loading Loading
django/contrib/admin/filters.py +4 −4 Original line number Diff line number Diff line Loading @@ -8,7 +8,7 @@ certain test -- e.g. being a DateField or ForeignKey. import datetime from django.db import models from django.db.models.fields.related import ManyToManyField from django.db.models.fields.related import ForeignObjectRel, ManyToManyField from django.core.exceptions import ImproperlyConfigured, ValidationError from django.utils.encoding import smart_text, force_text from django.utils.translation import ugettext_lazy as _ Loading Loading @@ -180,7 +180,7 @@ class RelatedFieldListFilter(FieldListFilter): self.title = self.lookup_title def has_output(self): if (isinstance(self.field, models.related.RelatedObject) and if (isinstance(self.field, ForeignObjectRel) and self.field.field.null or hasattr(self.field, 'rel') and self.field.null): extra = 1 Loading Loading @@ -210,7 +210,7 @@ class RelatedFieldListFilter(FieldListFilter): }, [self.lookup_kwarg_isnull]), 'display': val, } if (isinstance(self.field, models.related.RelatedObject) and if (isinstance(self.field, ForeignObjectRel) and (self.field.field.null or isinstance(self.field.field, ManyToManyField)) or hasattr(self.field, 'rel') and (self.field.null or isinstance(self.field, ManyToManyField))): yield { Loading @@ -223,7 +223,7 @@ class RelatedFieldListFilter(FieldListFilter): FieldListFilter.register(lambda f: ( bool(f.rel) if hasattr(f, 'rel') else isinstance(f, models.related.RelatedObject)), RelatedFieldListFilter) isinstance(f, ForeignObjectRel)), RelatedFieldListFilter) class BooleanFieldListFilter(FieldListFilter): Loading
django/contrib/admin/options.py +2 −2 Original line number Diff line number Diff line Loading @@ -25,8 +25,8 @@ from django.core.paginator import Paginator from django.core.urlresolvers import reverse from django.db import models, transaction, router from django.db.models.constants import LOOKUP_SEP from django.db.models.related import RelatedObject from django.db.models.fields import BLANK_CHOICE_DASH, FieldDoesNotExist from django.db.models.fields.related import ForeignObjectRel from django.db.models.sql.constants import QUERY_TERMS from django.forms.formsets import all_valid, DELETION_FIELD_NAME from django.forms.models import (modelform_factory, modelformset_factory, Loading Loading @@ -421,7 +421,7 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)): rel_name = field.rel.get_related_field().name else: rel_name = None elif isinstance(field, RelatedObject): elif isinstance(field, ForeignObjectRel): model = field.model rel_name = model._meta.pk.name else: Loading
django/contrib/admin/utils.py +1 −1 Original line number Diff line number Diff line Loading @@ -304,7 +304,7 @@ def label_for_field(name, model, model_admin=None, return_attr=False): try: label = field.verbose_name except AttributeError: # field is likely a RelatedObject # field is likely a ForeignObjectRel label = field.opts.verbose_name except models.FieldDoesNotExist: if name == "__unicode__": Loading
django/contrib/contenttypes/fields.py +2 −1 Original line number Diff line number Diff line Loading @@ -9,7 +9,7 @@ from django.db import models, router, transaction, DEFAULT_DB_ALIAS from django.db.models import signals, FieldDoesNotExist, DO_NOTHING from django.db.models.base import ModelBase from django.db.models.fields.related import ForeignObject, ForeignObjectRel from django.db.models.related import PathInfo from django.db.models.query_utils import PathInfo from django.db.models.expressions import Col from django.contrib.contenttypes.models import ContentType from django.utils.encoding import smart_text, python_2_unicode_compatible Loading @@ -27,6 +27,7 @@ class GenericForeignKey(object): self.fk_field = fk_field self.for_concrete_model = for_concrete_model self.editable = False self.rel = None def contribute_to_class(self, cls, name, **kwargs): self.name = name Loading
django/db/models/fields/related.py +106 −32 Original line number Diff line number Diff line from __future__ import unicode_literals from operator import attrgetter import warnings from django.apps import apps from django.core import checks Loading @@ -9,13 +10,15 @@ from django.db.backends import utils from django.db.models import signals, Q from django.db.models.deletion import SET_NULL, SET_DEFAULT, CASCADE from django.db.models.fields import (AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist) PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist, BLANK_CHOICE_DASH) from django.db.models.lookups import IsNull from django.db.models.related import RelatedObject, PathInfo from django.db.models.query import QuerySet from django.db.models.query_utils import PathInfo from django.db.models.expressions import Col from django.utils.encoding import force_text, smart_text from django.utils import six from django.utils.deprecation import RemovedInDjango20Warning from django.utils.translation import ugettext_lazy as _ from django.utils.functional import curry, cached_property from django.core import exceptions Loading Loading @@ -178,7 +181,7 @@ class RelatedField(Field): return [] try: self.related self.rel except AttributeError: return [] Loading @@ -195,7 +198,7 @@ class RelatedField(Field): rel_opts = self.rel.to._meta # rel_opts.object_name == "Target" rel_name = self.related.get_accessor_name() # i. e. "model_set" rel_name = self.rel.get_accessor_name() # i. e. "model_set" rel_query_name = self.related_query_name() # i. e. "model" field_name = "%s.%s" % (opts.object_name, self.name) # i. e. "Model.field" Loading Loading @@ -324,11 +327,17 @@ class RelatedField(Field): self.verbose_name = self.rel.to._meta.verbose_name self.rel.set_field_name() @property def related(self): warnings.warn( "Usage of field.related has been deprecated. Use field.rel instead.", RemovedInDjango20Warning, 2) return self.rel def do_related_class(self, other, cls): self.set_attributes_from_rel() self.related = RelatedObject(other, cls, self) if not cls._meta.abstract: self.contribute_to_related_class(other, self.related) self.contribute_to_related_class(other, self.rel) def get_limit_choices_to(self): """Returns 'limit_choices_to' for this model field. Loading Loading @@ -554,7 +563,7 @@ class ReverseSingleRelatedObjectDescriptor(object): # Since we're going to assign directly in the cache, # we must manage the reverse relation cache manually. if not self.field.rel.multiple: rel_obj_cache_name = self.field.related.get_cache_name() rel_obj_cache_name = self.field.rel.get_cache_name() for rel_obj in queryset: instance = instances_dict[rel_obj_attr(rel_obj)] setattr(rel_obj, rel_obj_cache_name, instance) Loading Loading @@ -583,7 +592,7 @@ class ReverseSingleRelatedObjectDescriptor(object): # Assuming the database enforces foreign keys, this won't fail. rel_obj = qs.get() if not self.field.rel.multiple: setattr(rel_obj, self.field.related.get_cache_name(), instance) setattr(rel_obj, self.field.rel.get_cache_name(), instance) setattr(instance, self.cache_name, rel_obj) if rel_obj is None and not self.field.null: raise self.RelatedObjectDoesNotExist( Loading Loading @@ -635,7 +644,7 @@ class ReverseSingleRelatedObjectDescriptor(object): # cache. This cache also might not exist if the related object # hasn't been accessed yet. if related is not None: setattr(related, self.field.related.get_cache_name(), None) setattr(related, self.field.rel.get_cache_name(), None) for lh_field, rh_field in self.field.related_fields: setattr(instance, lh_field.attname, None) Loading @@ -656,7 +665,7 @@ class ReverseSingleRelatedObjectDescriptor(object): # object you just set. setattr(instance, self.cache_name, value) if value is not None and not self.field.rel.multiple: setattr(value, self.field.related.get_cache_name(), instance) setattr(value, self.field.rel.get_cache_name(), instance) def create_foreign_related_manager(superclass, rel_field, rel_model): Loading Loading @@ -1248,13 +1257,6 @@ class ReverseManyRelatedObjectsDescriptor(object): class ForeignObjectRel(object): def __init__(self, field, to, related_name=None, limit_choices_to=None, parent_link=False, on_delete=None, related_query_name=None): try: to._meta except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT assert isinstance(to, six.string_types), ( "'to' must be either a model, a model name or the string %r" % RECURSIVE_RELATIONSHIP_CONSTANT ) self.field = field self.to = to self.related_name = related_name Loading @@ -1263,6 +1265,56 @@ class ForeignObjectRel(object): self.multiple = True self.parent_link = parent_link self.on_delete = on_delete self.symmetrical = False # This and the following cached_properties can't be initialized in # __init__ as the field doesn't have its model yet. Calling these methods # before field.contribute_to_class() has been called will result in # AttributeError @cached_property def model(self): if not self.field.model: raise AttributeError( "This property can't be accessed before self.field.contribute_to_class has been called.") return self.field.model @cached_property def opts(self): return self.model._meta @cached_property def to_opts(self): return self.to._meta @cached_property def parent_model(self): return self.to @cached_property def name(self): return '%s.%s' % (self.opts.app_label, self.opts.model_name) def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH, limit_to_currently_related=False): """ Returns choices with a default blank choices included, for use as SelectField choices for this field. Analog of django.db.models.fields.Field.get_choices(), provided initially for utilization by RelatedFieldListFilter. """ first_choice = blank_choice if include_blank else [] queryset = self.model._default_manager.all() if limit_to_currently_related: queryset = queryset.complex_filter( {'%s__isnull' % self.parent_model._meta.model_name: False} ) lst = [(x._get_pk_val(), smart_text(x)) for x in queryset] return first_choice + lst def get_db_prep_lookup(self, lookup_type, value, connection, prepared=False): # Defer to the actual field definition for db prep return self.field.get_db_prep_lookup(lookup_type, value, connection=connection, prepared=prepared) def is_hidden(self): "Should the related object be hidden?" Loading @@ -1289,6 +1341,34 @@ class ForeignObjectRel(object): return self.field.get_lookup_constraint(constraint_class, alias, targets, sources, lookup_type, raw_value) def get_accessor_name(self, model=None): # This method encapsulates the logic that decides what name to give an # accessor descriptor that retrieves related many-to-one or # many-to-many objects. It uses the lower-cased object_name + "_set", # but this can be overridden with the "related_name" option. # Due to backwards compatibility ModelForms need to be able to provide # an alternate model. See BaseInlineFormSet.get_default_prefix(). opts = model._meta if model else self.opts model = model or self.model if self.multiple: # If this is a symmetrical m2m relation on self, there is no reverse accessor. if self.symmetrical and model == self.to: return None if self.related_name: return self.related_name if opts.default_related_name: return self.opts.default_related_name % { 'model_name': self.opts.model_name.lower(), 'app_label': self.opts.app_label.lower(), } return opts.model_name + ('_set' if self.multiple else '') def get_cache_name(self): return "_%s_cache" % self.get_accessor_name() def get_path_info(self): return self.field.get_reverse_path_info() class ManyToOneRel(ForeignObjectRel): def __init__(self, field, to, field_name, related_name=None, limit_choices_to=None, Loading Loading @@ -1322,30 +1402,23 @@ class OneToOneRel(ManyToOneRel): self.multiple = False class ManyToManyRel(object): def __init__(self, to, related_name=None, limit_choices_to=None, class ManyToManyRel(ForeignObjectRel): def __init__(self, field, to, related_name=None, limit_choices_to=None, symmetrical=True, through=None, through_fields=None, db_constraint=True, related_query_name=None): if through and not db_constraint: raise ValueError("Can't supply a through model and db_constraint=False") if through_fields and not through: raise ValueError("Cannot specify through_fields without a through model") self.to = to self.related_name = related_name self.related_query_name = related_query_name if limit_choices_to is None: limit_choices_to = {} self.limit_choices_to = limit_choices_to super(ManyToManyRel, self).__init__( field, to, related_name=related_name, limit_choices_to=limit_choices_to, related_query_name=related_query_name) self.symmetrical = symmetrical self.multiple = True self.through = through self.through_fields = through_fields self.db_constraint = db_constraint def is_hidden(self): "Should the related object be hidden?" return self.related_name and self.related_name[-1] == '+' def get_related_field(self): """ Returns the field in the 'to' object to which this relationship is tied. Loading Loading @@ -1402,7 +1475,7 @@ class ForeignObject(RelatedField): return [] try: self.related self.rel except AttributeError: return [] Loading Loading @@ -1979,7 +2052,8 @@ class ManyToManyField(RelatedField): to = str(to) kwargs['verbose_name'] = kwargs.get('verbose_name', None) kwargs['rel'] = ManyToManyRel(to, kwargs['rel'] = ManyToManyRel( self, to, related_name=kwargs.pop('related_name', None), related_query_name=kwargs.pop('related_query_name', None), limit_choices_to=kwargs.pop('limit_choices_to', None), Loading