Explorar el Código

Renamed Field.rel attribute to remote_field

Field.rel is now deprecated. Rel objects have now also remote_field
attribute. This means that self == self.remote_field.remote_field.

In addition, made the Rel objects a bit more like Field objects. Still,
marked ManyToManyFields as null=True.
Anssi Kääriäinen hace 10 años
padre
commit
8f30556329
Se han modificado 62 ficheros con 588 adiciones y 586 borrados
  1. 1 1
      django/contrib/admin/checks.py
  2. 5 24
      django/contrib/admin/filters.py
  3. 1 1
      django/contrib/admin/helpers.py
  4. 30 46
      django/contrib/admin/options.py
  5. 1 1
      django/contrib/admin/templatetags/admin_list.py
  6. 1 21
      django/contrib/admin/utils.py
  7. 1 1
      django/contrib/admin/views/main.py
  8. 6 6
      django/contrib/admin/widgets.py
  9. 4 4
      django/contrib/admindocs/views.py
  10. 1 1
      django/contrib/auth/admin.py
  11. 9 4
      django/contrib/auth/management/commands/createsuperuser.py
  12. 12 11
      django/contrib/contenttypes/fields.py
  13. 1 1
      django/contrib/contenttypes/forms.py
  14. 2 2
      django/contrib/contenttypes/views.py
  15. 1 1
      django/contrib/gis/db/models/lookups.py
  16. 1 1
      django/contrib/gis/utils/layermapping.py
  17. 1 1
      django/contrib/postgres/fields/array.py
  18. 4 4
      django/core/serializers/__init__.py
  19. 1 1
      django/core/serializers/base.py
  20. 15 15
      django/core/serializers/python.py
  21. 17 17
      django/core/serializers/xml_serializer.py
  22. 1 1
      django/db/backends/base/introspection.py
  23. 34 34
      django/db/backends/base/schema.py
  24. 1 1
      django/db/backends/mysql/validation.py
  25. 1 1
      django/db/backends/oracle/operations.py
  26. 1 1
      django/db/backends/postgresql_psycopg2/operations.py
  27. 14 14
      django/db/backends/sqlite3/schema.py
  28. 33 33
      django/db/migrations/autodetector.py
  29. 5 5
      django/db/migrations/operations/fields.py
  30. 11 11
      django/db/migrations/operations/models.py
  31. 4 4
      django/db/migrations/optimizer.py
  32. 3 3
      django/db/migrations/state.py
  33. 16 16
      django/db/models/base.py
  34. 8 9
      django/db/models/deletion.py
  35. 17 9
      django/db/models/fields/__init__.py
  36. 220 190
      django/db/models/fields/related.py
  37. 2 2
      django/db/models/fields/related_lookups.py
  38. 9 9
      django/db/models/options.py
  39. 2 2
      django/db/models/query.py
  40. 2 2
      django/db/models/query_utils.py
  41. 4 4
      django/db/models/sql/compiler.py
  42. 2 2
      django/db/models/sql/query.py
  43. 15 15
      django/forms/models.py
  44. 4 0
      docs/internals/deprecation.txt
  45. 9 0
      docs/releases/1.9.txt
  46. 10 10
      tests/admin_widgets/tests.py
  47. 1 1
      tests/backends/tests.py
  48. 1 1
      tests/basic/tests.py
  49. 1 1
      tests/delete/tests.py
  50. 2 2
      tests/field_deconstruction/tests.py
  51. 1 1
      tests/foreign_object/models.py
  52. 3 3
      tests/many_to_one/tests.py
  53. 5 5
      tests/migrations/test_autodetector.py
  54. 6 6
      tests/migrations/test_operations.py
  55. 3 3
      tests/model_fields/test_field_flags.py
  56. 1 1
      tests/model_fields/tests.py
  57. 1 1
      tests/model_meta/tests.py
  58. 2 2
      tests/model_options/models/tablespaces.py
  59. 2 2
      tests/one_to_one/tests.py
  60. 1 1
      tests/queryset_pickle/tests.py
  61. 6 5
      tests/schema/fields.py
  62. 9 9
      tests/schema/tests.py

+ 1 - 1
django/contrib/admin/checks.py

@@ -180,7 +180,7 @@ class BaseModelAdminChecks(object):
                 return []
             else:
                 if (isinstance(field, models.ManyToManyField) and
-                        not field.rel.through._meta.auto_created):
+                        not field.remote_field.through._meta.auto_created):
                     return [
                         checks.Error(
                             ("The value of '%s' cannot include the ManyToManyField '%s', "

+ 5 - 24
django/contrib/admin/filters.py

@@ -9,12 +9,10 @@ import datetime
 
 from django.contrib.admin.options import IncorrectLookupParameters
 from django.contrib.admin.utils import (
-    get_limit_choices_to_from_path, get_model_from_relation,
-    prepare_lookup_value, reverse_field_path,
+    get_model_from_relation, prepare_lookup_value, reverse_field_path,
 )
 from django.core.exceptions import ImproperlyConfigured, ValidationError
 from django.db import models
-from django.db.models.fields.related import ForeignObjectRel, ManyToManyField
 from django.utils import timezone
 from django.utils.encoding import force_text, smart_text
 from django.utils.translation import ugettext_lazy as _
@@ -164,11 +162,7 @@ class FieldListFilter(ListFilter):
 class RelatedFieldListFilter(FieldListFilter):
     def __init__(self, field, request, params, model, model_admin, field_path):
         other_model = get_model_from_relation(field)
-        if hasattr(field, 'rel'):
-            rel_name = field.rel.get_related_field().name
-        else:
-            rel_name = other_model._meta.pk.name
-        self.lookup_kwarg = '%s__%s__exact' % (field_path, rel_name)
+        self.lookup_kwarg = '%s__%s__exact' % (field_path, field.target_field.name)
         self.lookup_kwarg_isnull = '%s__isnull' % field_path
         self.lookup_val = request.GET.get(self.lookup_kwarg)
         self.lookup_val_isnull = request.GET.get(self.lookup_kwarg_isnull)
@@ -182,9 +176,7 @@ class RelatedFieldListFilter(FieldListFilter):
         self.title = self.lookup_title
 
     def has_output(self):
-        if (isinstance(self.field, ForeignObjectRel) and
-                self.field.field.null or hasattr(self.field, 'rel') and
-                self.field.null):
+        if self.field.null:
             extra = 1
         else:
             extra = 0
@@ -212,9 +204,7 @@ class RelatedFieldListFilter(FieldListFilter):
                 }, [self.lookup_kwarg_isnull]),
                 'display': val,
             }
-        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))):
+        if self.field.null:
             yield {
                 'selected': bool(self.lookup_val_isnull),
                 'query_string': cl.get_query_string({
@@ -223,9 +213,7 @@ class RelatedFieldListFilter(FieldListFilter):
                 'display': EMPTY_CHANGELIST_VALUE,
             }
 
-FieldListFilter.register(lambda f: (
-    bool(f.rel) if hasattr(f, 'rel') else
-    isinstance(f, ForeignObjectRel)), RelatedFieldListFilter)
+FieldListFilter.register(lambda f: f.remote_field, RelatedFieldListFilter)
 
 
 class BooleanFieldListFilter(FieldListFilter):
@@ -371,13 +359,6 @@ class AllValuesFieldListFilter(FieldListFilter):
             queryset = model_admin.get_queryset(request)
         else:
             queryset = parent_model._default_manager.all()
-
-        # optional feature: limit choices base on existing relationships
-        # queryset = queryset.complex_filter(
-        #    {'%s__isnull' % reverse_path: False})
-        limit_choices_to = get_limit_choices_to_from_path(model, field_path)
-        queryset = queryset.filter(limit_choices_to)
-
         self.lookup_choices = (queryset
                                .distinct()
                                .order_by(field.name)

+ 1 - 1
django/contrib/admin/helpers.py

@@ -203,7 +203,7 @@ class AdminReadonlyField(object):
                     else:
                         result_repr = linebreaksbr(result_repr)
             else:
-                if isinstance(f.rel, ManyToManyRel) and value is not None:
+                if isinstance(f.remote_field, ManyToManyRel) and value is not None:
                     result_repr = ", ".join(map(six.text_type, value.all()))
                 else:
                     result_repr = display_for_field(value, f)

+ 30 - 46
django/contrib/admin/options.py

@@ -26,8 +26,6 @@ from django.core.urlresolvers import reverse
 from django.db import models, router, transaction
 from django.db.models.constants import LOOKUP_SEP
 from django.db.models.fields import BLANK_CHOICE_DASH
-from django.db.models.fields.related import ForeignObjectRel
-from django.db.models.sql.constants import QUERY_TERMS
 from django.forms.formsets import DELETION_FIELD_NAME, all_valid
 from django.forms.models import (
     BaseInlineFormSet, inlineformset_factory, modelform_defines_fields,
@@ -154,7 +152,7 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
             # rendered output. formfield can be None if it came from a
             # OneToOneField with parent_link=True or a M2M intermediary.
             if formfield and db_field.name not in self.raw_id_fields:
-                related_modeladmin = self.admin_site._registry.get(db_field.rel.to)
+                related_modeladmin = self.admin_site._registry.get(db_field.remote_field.model)
                 wrapper_kwargs = {}
                 if related_modeladmin:
                     wrapper_kwargs.update(
@@ -163,7 +161,7 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
                         can_delete_related=related_modeladmin.has_delete_permission(request),
                     )
                 formfield.widget = widgets.RelatedFieldWidgetWrapper(
-                    formfield.widget, db_field.rel, self.admin_site, **wrapper_kwargs
+                    formfield.widget, db_field.remote_field, self.admin_site, **wrapper_kwargs
                 )
 
             return formfield
@@ -202,11 +200,11 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
         ordering.  Otherwise don't specify the queryset, let the field decide
         (returns None in that case).
         """
-        related_admin = self.admin_site._registry.get(db_field.rel.to, None)
+        related_admin = self.admin_site._registry.get(db_field.remote_field.model, None)
         if related_admin is not None:
             ordering = related_admin.get_ordering(request)
             if ordering is not None and ordering != ():
-                return db_field.rel.to._default_manager.using(db).order_by(*ordering)
+                return db_field.remote_field.model._default_manager.using(db).order_by(*ordering)
         return None
 
     def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
@@ -215,7 +213,7 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
         """
         db = kwargs.get('using')
         if db_field.name in self.raw_id_fields:
-            kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel,
+            kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.remote_field,
                                     self.admin_site, using=db)
         elif db_field.name in self.radio_fields:
             kwargs['widget'] = widgets.AdminRadioSelect(attrs={
@@ -236,12 +234,12 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
         """
         # If it uses an intermediary model that isn't auto created, don't show
         # a field in admin.
-        if not db_field.rel.through._meta.auto_created:
+        if not db_field.remote_field.through._meta.auto_created:
             return None
         db = kwargs.get('using')
 
         if db_field.name in self.raw_id_fields:
-            kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel,
+            kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.remote_field,
                                     self.admin_site, using=db)
             kwargs['help_text'] = ''
         elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)):
@@ -334,46 +332,32 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
                 if k == lookup and v == value:
                     return True
 
-        parts = lookup.split(LOOKUP_SEP)
-
-        # Last term in lookup is a query term (__exact, __startswith etc)
-        # This term can be ignored.
-        if len(parts) > 1 and parts[-1] in QUERY_TERMS:
-            parts.pop()
-
-        # Special case -- foo__id__exact and foo__id queries are implied
-        # if foo has been specifically included in the lookup list; so
-        # drop __id if it is the last part. However, first we need to find
-        # the pk attribute name.
-        rel_name = None
-        for part in parts[:-1]:
+        relation_parts = []
+        prev_field = None
+        for part in lookup.split(LOOKUP_SEP):
             try:
                 field = model._meta.get_field(part)
             except FieldDoesNotExist:
                 # Lookups on non-existent fields are ok, since they're ignored
                 # later.
-                return True
-            if hasattr(field, 'rel'):
-                if field.rel is None:
-                    # This property or relation doesn't exist, but it's allowed
-                    # since it's ignored in ChangeList.get_filters().
-                    return True
-                model = field.rel.to
-                if hasattr(field.rel, 'get_related_field'):
-                    rel_name = field.rel.get_related_field().name
-                else:
-                    rel_name = None
-            elif isinstance(field, ForeignObjectRel):
-                model = field.related_model
-                rel_name = model._meta.pk.name
-            else:
-                rel_name = None
-        if rel_name and len(parts) > 1 and parts[-1] == rel_name:
-            parts.pop()
-
-        if len(parts) == 1:
+                break
+            # It is allowed to filter on values that would be found from local
+            # model anyways. For example, if you filter on employee__department__id,
+            # then the id value would be found already from employee__department_id.
+            if not prev_field or (prev_field.concrete and
+                                  field not in prev_field.get_path_info()[-1].target_fields):
+                relation_parts.append(part)
+            if not getattr(field, 'get_path_info', None):
+                # This is not a relational field, so further parts
+                # must be transforms.
+                break
+            prev_field = field
+            model = field.get_path_info()[-1].to_opts.model
+
+        if len(relation_parts) <= 1:
+            # Either a local field filter, or no fields at all.
             return True
-        clean_lookup = LOOKUP_SEP.join(parts)
+        clean_lookup = LOOKUP_SEP.join(relation_parts)
         valid_lookups = [self.date_hierarchy]
         for filter_item in self.list_filter:
             if isinstance(filter_item, type) and issubclass(filter_item, SimpleListFilter):
@@ -422,7 +406,7 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
         for related_object in related_objects:
             related_model = related_object.related_model
             if (any(issubclass(model, related_model) for model in registered_models) and
-                    related_object.field.rel.get_related_field() == field):
+                    related_object.field.remote_field.get_related_field() == field):
                 return True
 
         return False
@@ -1882,8 +1866,8 @@ class InlineModelAdmin(BaseModelAdmin):
             # The model was auto-created as intermediary for a
             # ManyToMany-relationship, find the target model
             for field in opts.fields:
-                if field.rel and field.rel.to != self.parent_model:
-                    opts = field.rel.to._meta
+                if field.remote_field and field.remote_field.model != self.parent_model:
+                    opts = field.remote_field.model._meta
                     break
         codename = get_permission_codename('change', opts)
         return request.user.has_perm("%s.%s" % (opts.app_label, codename))

+ 1 - 1
django/contrib/admin/templatetags/admin_list.py

@@ -215,7 +215,7 @@ def items_for_result(cl, result, form):
                 if isinstance(value, (datetime.date, datetime.time)):
                     row_classes.append('nowrap')
             else:
-                if isinstance(f.rel, models.ManyToOneRel):
+                if isinstance(f.remote_field, models.ManyToOneRel):
                     field_val = getattr(result, f.name)
                     if field_val is None:
                         result_repr = EMPTY_CHANGELIST_VALUE

+ 1 - 21
django/contrib/admin/utils.py

@@ -446,7 +446,7 @@ def reverse_field_path(model, path):
         # Field should point to another model
         if field.is_relation and not (field.auto_created and not field.concrete):
             related_name = field.related_query_name()
-            parent = field.rel.to
+            parent = field.remote_field.model
         else:
             related_name = field.field.name
             parent = field.related_model
@@ -481,23 +481,3 @@ def remove_trailing_data_field(fields):
     except NotRelationField:
         fields = fields[:-1]
     return fields
-
-
-def get_limit_choices_to_from_path(model, path):
-    """ Return Q object for limiting choices if applicable.
-
-    If final model in path is linked via a ForeignKey or ManyToManyField which
-    has a ``limit_choices_to`` attribute, return it as a Q object.
-    """
-    fields = get_fields_from_path(model, path)
-    fields = remove_trailing_data_field(fields)
-    get_limit_choices_to = (
-        fields and hasattr(fields[-1], 'rel') and
-        getattr(fields[-1].rel, 'get_limit_choices_to', None))
-    if not get_limit_choices_to:
-        return models.Q()  # empty Q
-    limit_choices_to = get_limit_choices_to()
-    if isinstance(limit_choices_to, models.Q):
-        return limit_choices_to  # already a Q
-    else:
-        return models.Q(**limit_choices_to)  # convert dict to Q

+ 1 - 1
django/contrib/admin/views/main.py

@@ -383,7 +383,7 @@ class ChangeList(object):
             except FieldDoesNotExist:
                 pass
             else:
-                if isinstance(field.rel, models.ManyToOneRel):
+                if isinstance(field.remote_field, models.ManyToOneRel):
                     return True
         return False
 

+ 6 - 6
django/contrib/admin/widgets.py

@@ -151,7 +151,7 @@ class ForeignKeyRawIdWidget(forms.TextInput):
         super(ForeignKeyRawIdWidget, self).__init__(attrs)
 
     def render(self, name, value, attrs=None):
-        rel_to = self.rel.to
+        rel_to = self.rel.model
         if attrs is None:
             attrs = {}
         extra = []
@@ -196,9 +196,9 @@ class ForeignKeyRawIdWidget(forms.TextInput):
     def label_for_value(self, value):
         key = self.rel.get_related_field().name
         try:
-            obj = self.rel.to._default_manager.using(self.db).get(**{key: value})
+            obj = self.rel.model._default_manager.using(self.db).get(**{key: value})
             return '&nbsp;<strong>%s</strong>' % escape(Truncator(obj).words(14, truncate='...'))
-        except (ValueError, self.rel.to.DoesNotExist):
+        except (ValueError, self.rel.model.DoesNotExist):
             return ''
 
 
@@ -210,7 +210,7 @@ class ManyToManyRawIdWidget(ForeignKeyRawIdWidget):
     def render(self, name, value, attrs=None):
         if attrs is None:
             attrs = {}
-        if self.rel.to in self.admin_site._registry:
+        if self.rel.model in self.admin_site._registry:
             # The related object is registered with the same AdminSite
             attrs['class'] = 'vManyToManyRawIdAdminField'
         if value:
@@ -248,7 +248,7 @@ class RelatedFieldWidgetWrapper(forms.Widget):
         # Backwards compatible check for whether a user can add related
         # objects.
         if can_add_related is None:
-            can_add_related = rel.to in admin_site._registry
+            can_add_related = rel.model in admin_site._registry
         self.can_add_related = can_add_related
         # XXX: The UX does not support multiple selected values.
         multiple = getattr(widget, 'allow_multiple_selected', False)
@@ -280,7 +280,7 @@ class RelatedFieldWidgetWrapper(forms.Widget):
 
     def render(self, name, value, *args, **kwargs):
         from django.contrib.admin.views.main import IS_POPUP_VAR, TO_FIELD_VAR
-        rel_opts = self.rel.to._meta
+        rel_opts = self.rel.model._meta
         info = (rel_opts.app_label, rel_opts.model_name)
         self.widget.choices = self.choices
         url_params = '&'.join("%s=%s" % param for param in [

+ 4 - 4
django/contrib/admindocs/views.py

@@ -207,8 +207,8 @@ class ModelDetailView(BaseAdminDocsView):
             # ForeignKey is a special case since the field will actually be a
             # descriptor that returns the other object
             if isinstance(field, models.ForeignKey):
-                data_type = field.rel.to.__name__
-                app_label = field.rel.to._meta.app_label
+                data_type = field.remote_field.model.__name__
+                app_label = field.remote_field.model._meta.app_label
                 verbose = utils.parse_rst(
                     (_("the related `%(app_label)s.%(data_type)s` object") % {
                         'app_label': app_label, 'data_type': data_type,
@@ -228,8 +228,8 @@ class ModelDetailView(BaseAdminDocsView):
 
         # Gather many-to-many fields.
         for field in opts.many_to_many:
-            data_type = field.rel.to.__name__
-            app_label = field.rel.to._meta.app_label
+            data_type = field.remote_field.model.__name__
+            app_label = field.remote_field.model._meta.app_label
             verbose = _("related `%(app_label)s.%(object_name)s` objects") % {
                 'app_label': app_label,
                 'object_name': data_type,

+ 1 - 1
django/contrib/auth/admin.py

@@ -31,7 +31,7 @@ class GroupAdmin(admin.ModelAdmin):
 
     def formfield_for_manytomany(self, db_field, request=None, **kwargs):
         if db_field.name == 'permissions':
-            qs = kwargs.get('queryset', db_field.rel.to.objects)
+            qs = kwargs.get('queryset', db_field.remote_field.model.objects)
             # Avoid a major performance hit resolving permission names which
             # triggers a content_type load:
             kwargs['queryset'] = qs.select_related('content_type')

+ 9 - 4
django/contrib/auth/management/commands/createsuperuser.py

@@ -90,11 +90,11 @@ class Command(BaseCommand):
                     input_msg = capfirst(verbose_field_name)
                     if default_username:
                         input_msg += " (leave blank to use '%s')" % default_username
-                    username_rel = self.username_field.rel
+                    username_rel = self.username_field.remote_field
                     input_msg = force_str('%s%s: ' % (
                         input_msg,
                         ' (%s.%s)' % (
-                            username_rel.to._meta.object_name,
+                            username_rel.model._meta.object_name,
                             username_rel.field_name
                         ) if username_rel else '')
                     )
@@ -114,8 +114,13 @@ class Command(BaseCommand):
                     field = self.UserModel._meta.get_field(field_name)
                     user_data[field_name] = options.get(field_name)
                     while user_data[field_name] is None:
-                        message = force_str('%s%s: ' % (capfirst(field.verbose_name),
-                            ' (%s.%s)' % (field.rel.to._meta.object_name, field.rel.field_name) if field.rel else ''))
+                        message = force_str('%s%s: ' % (
+                            capfirst(field.verbose_name),
+                            ' (%s.%s)' % (
+                                field.remote_field.model._meta.object_name,
+                                field.remote_field.field_name,
+                            ) if field.remote_field else '',
+                        ))
                         user_data[field_name] = self.get_input_data(field, message)
 
                 # Get a password

+ 12 - 11
django/contrib/contenttypes/fields.py

@@ -39,6 +39,7 @@ class GenericForeignKey(object):
     one_to_many = False
     one_to_one = False
     related_model = None
+    remote_field = None
 
     allow_unsaved_instance_assignment = False
 
@@ -135,7 +136,7 @@ class GenericForeignKey(object):
                         id='contenttypes.E003',
                     )
                 ]
-            elif field.rel.to != ContentType:
+            elif field.remote_field.model != ContentType:
                 return [
                     checks.Error(
                         "'%s.%s' is not a ForeignKey to 'contenttypes.ContentType'." % (
@@ -323,7 +324,7 @@ class GenericRelation(ForeignObject):
         return errors
 
     def _check_generic_foreign_key_existence(self):
-        target = self.rel.to
+        target = self.remote_field.model
         if isinstance(target, ModelBase):
             fields = target._meta.virtual_fields
             if any(isinstance(field, GenericForeignKey) and
@@ -348,16 +349,16 @@ class GenericRelation(ForeignObject):
 
     def resolve_related_fields(self):
         self.to_fields = [self.model._meta.pk.name]
-        return [(self.rel.to._meta.get_field(self.object_id_field_name), self.model._meta.pk)]
+        return [(self.remote_field.model._meta.get_field(self.object_id_field_name), self.model._meta.pk)]
 
     def get_path_info(self):
-        opts = self.rel.to._meta
+        opts = self.remote_field.model._meta
         target = opts.pk
-        return [PathInfo(self.model._meta, opts, (target,), self.rel, True, False)]
+        return [PathInfo(self.model._meta, opts, (target,), self.remote_field, True, False)]
 
     def get_reverse_path_info(self):
         opts = self.model._meta
-        from_opts = self.rel.to._meta
+        from_opts = self.remote_field.model._meta
         return [PathInfo(from_opts, opts, (opts.pk,), self, not self.unique, False)]
 
     def get_choices_default(self):
@@ -371,7 +372,7 @@ class GenericRelation(ForeignObject):
         kwargs['virtual_only'] = True
         super(GenericRelation, self).contribute_to_class(cls, name, **kwargs)
         self.model = cls
-        setattr(cls, self.name, ReverseGenericRelatedObjectsDescriptor(self.rel))
+        setattr(cls, self.name, ReverseGenericRelatedObjectsDescriptor(self.remote_field))
 
     def set_attributes_from_rel(self):
         pass
@@ -387,7 +388,7 @@ class GenericRelation(ForeignObject):
                                                  for_concrete_model=self.for_concrete_model)
 
     def get_extra_restriction(self, where_class, alias, remote_alias):
-        field = self.rel.to._meta.get_field(self.content_type_field_name)
+        field = self.remote_field.model._meta.get_field(self.content_type_field_name)
         contenttype_pk = self.get_content_type().pk
         cond = where_class()
         lookup = field.get_lookup('exact')(field.get_col(remote_alias), contenttype_pk)
@@ -398,7 +399,7 @@ class GenericRelation(ForeignObject):
         """
         Return all objects related to ``objs`` via this ``GenericRelation``.
         """
-        return self.rel.to._base_manager.db_manager(using).filter(**{
+        return self.remote_field.model._base_manager.db_manager(using).filter(**{
             "%s__pk" % self.content_type_field_name: ContentType.objects.db_manager(using).get_for_model(
                 self.model, for_concrete_model=self.for_concrete_model).pk,
             "%s__in" % self.object_id_field_name: [obj.pk for obj in objs]
@@ -421,7 +422,7 @@ class ReverseGenericRelatedObjectsDescriptor(ForeignRelatedObjectsDescriptor):
     @cached_property
     def related_manager_cls(self):
         return create_generic_related_manager(
-            self.rel.to._default_manager.__class__,
+            self.rel.model._default_manager.__class__,
             self.rel,
         )
 
@@ -439,7 +440,7 @@ def create_generic_related_manager(superclass, rel):
 
             self.instance = instance
 
-            self.model = rel.to
+            self.model = rel.model
 
             content_type = ContentType.objects.db_manager(instance._state.db).get_for_model(
                 instance, for_concrete_model=rel.field.for_concrete_model)

+ 1 - 1
django/contrib/contenttypes/forms.py

@@ -68,7 +68,7 @@ def generic_inlineformset_factory(model, form=ModelForm,
     opts = model._meta
     # if there is no field called `ct_field` let the exception propagate
     ct_field = opts.get_field(ct_field)
-    if not isinstance(ct_field, models.ForeignKey) or ct_field.rel.to != ContentType:
+    if not isinstance(ct_field, models.ForeignKey) or ct_field.remote_field.model != ContentType:
         raise Exception("fk_name '%s' is not a ForeignKey to ContentType" % ct_field)
     fk_field = opts.get_field(fk_field)  # let the exception propagate
     if exclude is not None:

+ 2 - 2
django/contrib/contenttypes/views.py

@@ -48,7 +48,7 @@ def shortcut(request, content_type_id, object_id):
 
         # First, look for an many-to-many relationship to Site.
         for field in opts.many_to_many:
-            if field.rel.to is Site:
+            if field.remote_field.model is Site:
                 try:
                     # Caveat: In the case of multiple related Sites, this just
                     # selects the *first* one, which is arbitrary.
@@ -61,7 +61,7 @@ def shortcut(request, content_type_id, object_id):
         # Next, look for a many-to-one relationship to Site.
         if object_domain is None:
             for field in obj._meta.fields:
-                if field.rel and field.rel.to is Site:
+                if field.remote_field and field.remote_field.model is Site:
                     try:
                         object_domain = getattr(obj, field.name).domain
                     except Site.DoesNotExist:

+ 1 - 1
django/contrib/gis/db/models/lookups.py

@@ -45,7 +45,7 @@ class GISLookup(Lookup):
             # model field associated with the next field in the list
             # until there's no more left.
             while len(field_list):
-                opts = geo_fld.rel.to._meta
+                opts = geo_fld.remote_field.model._meta
                 geo_fld = opts.get_field(field_list.pop())
         except (FieldDoesNotExist, AttributeError):
             return False

+ 1 - 1
django/contrib/gis/utils/layermapping.py

@@ -229,7 +229,7 @@ class LayerMapping(object):
             elif isinstance(model_field, models.ForeignKey):
                 if isinstance(ogr_name, dict):
                     # Is every given related model mapping field in the Layer?
-                    rel_model = model_field.rel.to
+                    rel_model = model_field.remote_field.model
                     for rel_name, ogr_field in ogr_name.items():
                         idx = check_ogr_fld(ogr_field)
                         try:

+ 1 - 1
django/contrib/postgres/fields/array.py

@@ -33,7 +33,7 @@ class ArrayField(Field):
 
     def check(self, **kwargs):
         errors = super(ArrayField, self).check(**kwargs)
-        if self.base_field.rel:
+        if self.base_field.remote_field:
             errors.append(
                 checks.Error(
                     'Base field for array cannot be a related field.',

+ 4 - 4
django/core/serializers/__init__.py

@@ -184,16 +184,16 @@ def sort_dependencies(app_list):
             # Now add a dependency for any FK relation with a model that
             # defines a natural key
             for field in model._meta.fields:
-                if hasattr(field.rel, 'to'):
-                    rel_model = field.rel.to
+                if field.remote_field:
+                    rel_model = field.remote_field.model
                     if hasattr(rel_model, 'natural_key') and rel_model != model:
                         deps.append(rel_model)
             # Also add a dependency for any simple M2M relation with a model
             # that defines a natural key.  M2M relations with explicit through
             # models don't count as dependencies.
             for field in model._meta.many_to_many:
-                if field.rel.through._meta.auto_created:
-                    rel_model = field.rel.to
+                if field.remote_field.through._meta.auto_created:
+                    rel_model = field.remote_field.model
                     if hasattr(rel_model, 'natural_key') and rel_model != model:
                         deps.append(rel_model)
             model_dependencies.append((model, deps))

+ 1 - 1
django/core/serializers/base.py

@@ -49,7 +49,7 @@ class Serializer(object):
             concrete_model = obj._meta.concrete_model
             for field in concrete_model._meta.local_fields:
                 if field.serialize:
-                    if field.rel is None:
+                    if field.remote_field is None:
                         if self.selected_fields is None or field.attname in self.selected_fields:
                             self.handle_field(obj, field)
                     else:

+ 15 - 15
django/core/serializers/python.py

@@ -55,7 +55,7 @@ class Serializer(base.Serializer):
             self._current[field.name] = field.value_to_string(obj)
 
     def handle_fk_field(self, obj, field):
-        if self.use_natural_foreign_keys and hasattr(field.rel.to, 'natural_key'):
+        if self.use_natural_foreign_keys and hasattr(field.remote_field.model, 'natural_key'):
             related = getattr(obj, field.name)
             if related:
                 value = related.natural_key()
@@ -68,8 +68,8 @@ class Serializer(base.Serializer):
         self._current[field.name] = value
 
     def handle_m2m_field(self, obj, field):
-        if field.rel.through._meta.auto_created:
-            if self.use_natural_foreign_keys and hasattr(field.rel.to, 'natural_key'):
+        if field.remote_field.through._meta.auto_created:
+            if self.use_natural_foreign_keys and hasattr(field.remote_field.model, 'natural_key'):
                 m2m_value = lambda value: value.natural_key()
             else:
                 m2m_value = lambda value: force_text(value._get_pk_val(), strings_only=True)
@@ -120,33 +120,33 @@ def Deserializer(object_list, **options):
             field = Model._meta.get_field(field_name)
 
             # Handle M2M relations
-            if field.rel and isinstance(field.rel, models.ManyToManyRel):
-                if hasattr(field.rel.to._default_manager, 'get_by_natural_key'):
+            if field.remote_field and isinstance(field.remote_field, models.ManyToManyRel):
+                if hasattr(field.remote_field.model._default_manager, 'get_by_natural_key'):
                     def m2m_convert(value):
                         if hasattr(value, '__iter__') and not isinstance(value, six.text_type):
-                            return field.rel.to._default_manager.db_manager(db).get_by_natural_key(*value).pk
+                            return field.remote_field.model._default_manager.db_manager(db).get_by_natural_key(*value).pk
                         else:
-                            return force_text(field.rel.to._meta.pk.to_python(value), strings_only=True)
+                            return force_text(field.remote_field.model._meta.pk.to_python(value), strings_only=True)
                 else:
-                    m2m_convert = lambda v: force_text(field.rel.to._meta.pk.to_python(v), strings_only=True)
+                    m2m_convert = lambda v: force_text(field.remote_field.model._meta.pk.to_python(v), strings_only=True)
                 m2m_data[field.name] = [m2m_convert(pk) for pk in field_value]
 
             # Handle FK fields
-            elif field.rel and isinstance(field.rel, models.ManyToOneRel):
+            elif field.remote_field and isinstance(field.remote_field, models.ManyToOneRel):
                 if field_value is not None:
-                    if hasattr(field.rel.to._default_manager, 'get_by_natural_key'):
+                    if hasattr(field.remote_field.model._default_manager, 'get_by_natural_key'):
                         if hasattr(field_value, '__iter__') and not isinstance(field_value, six.text_type):
-                            obj = field.rel.to._default_manager.db_manager(db).get_by_natural_key(*field_value)
-                            value = getattr(obj, field.rel.field_name)
+                            obj = field.remote_field.model._default_manager.db_manager(db).get_by_natural_key(*field_value)
+                            value = getattr(obj, field.remote_field.field_name)
                             # If this is a natural foreign key to an object that
                             # has a FK/O2O as the foreign key, use the FK value
-                            if field.rel.to._meta.pk.rel:
+                            if field.remote_field.model._meta.pk.remote_field:
                                 value = value.pk
                         else:
-                            value = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
+                            value = field.remote_field.model._meta.get_field(field.remote_field.field_name).to_python(field_value)
                         data[field.attname] = value
                     else:
-                        data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
+                        data[field.attname] = field.remote_field.model._meta.get_field(field.remote_field.field_name).to_python(field_value)
                 else:
                     data[field.attname] = None
 

+ 17 - 17
django/core/serializers/xml_serializer.py

@@ -91,7 +91,7 @@ class Serializer(base.Serializer):
         self._start_relational_field(field)
         related_att = getattr(obj, field.get_attname())
         if related_att is not None:
-            if self.use_natural_foreign_keys and hasattr(field.rel.to, 'natural_key'):
+            if self.use_natural_foreign_keys and hasattr(field.remote_field.model, 'natural_key'):
                 related = getattr(obj, field.name)
                 # If related object has a natural key, use it
                 related = related.natural_key()
@@ -112,9 +112,9 @@ class Serializer(base.Serializer):
         serialized as references to the object's PK (i.e. the related *data*
         is not dumped, just the relation).
         """
-        if field.rel.through._meta.auto_created:
+        if field.remote_field.through._meta.auto_created:
             self._start_relational_field(field)
-            if self.use_natural_foreign_keys and hasattr(field.rel.to, 'natural_key'):
+            if self.use_natural_foreign_keys and hasattr(field.remote_field.model, 'natural_key'):
                 # If the objects in the m2m have a natural key, use it
                 def handle_m2m(value):
                     natural = value.natural_key()
@@ -142,8 +142,8 @@ class Serializer(base.Serializer):
         self.indent(2)
         self.xml.startElement("field", {
             "name": field.name,
-            "rel": field.rel.__class__.__name__,
-            "to": smart_text(field.rel.to._meta),
+            "rel": field.remote_field.__class__.__name__,
+            "to": smart_text(field.remote_field.model._meta),
         })
 
 
@@ -204,9 +204,9 @@ class Deserializer(base.Deserializer):
             field = Model._meta.get_field(field_name)
 
             # As is usually the case, relation fields get the special treatment.
-            if field.rel and isinstance(field.rel, models.ManyToManyRel):
+            if field.remote_field and isinstance(field.remote_field, models.ManyToManyRel):
                 m2m_data[field.name] = self._handle_m2m_field_node(field_node, field)
-            elif field.rel and isinstance(field.rel, models.ManyToOneRel):
+            elif field.remote_field and isinstance(field.remote_field, models.ManyToOneRel):
                 data[field.attname] = self._handle_fk_field_node(field_node, field)
             else:
                 if field_node.getElementsByTagName('None'):
@@ -228,43 +228,43 @@ class Deserializer(base.Deserializer):
         if node.getElementsByTagName('None'):
             return None
         else:
-            if hasattr(field.rel.to._default_manager, 'get_by_natural_key'):
+            if hasattr(field.remote_field.model._default_manager, 'get_by_natural_key'):
                 keys = node.getElementsByTagName('natural')
                 if keys:
                     # If there are 'natural' subelements, it must be a natural key
                     field_value = [getInnerText(k).strip() for k in keys]
-                    obj = field.rel.to._default_manager.db_manager(self.db).get_by_natural_key(*field_value)
-                    obj_pk = getattr(obj, field.rel.field_name)
+                    obj = field.remote_field.model._default_manager.db_manager(self.db).get_by_natural_key(*field_value)
+                    obj_pk = getattr(obj, field.remote_field.field_name)
                     # If this is a natural foreign key to an object that
                     # has a FK/O2O as the foreign key, use the FK value
-                    if field.rel.to._meta.pk.rel:
+                    if field.remote_field.model._meta.pk.remote_field:
                         obj_pk = obj_pk.pk
                 else:
                     # Otherwise, treat like a normal PK
                     field_value = getInnerText(node).strip()
-                    obj_pk = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
+                    obj_pk = field.remote_field.model._meta.get_field(field.remote_field.field_name).to_python(field_value)
                 return obj_pk
             else:
                 field_value = getInnerText(node).strip()
-                return field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
+                return field.remote_field.model._meta.get_field(field.remote_field.field_name).to_python(field_value)
 
     def _handle_m2m_field_node(self, node, field):
         """
         Handle a <field> node for a ManyToManyField.
         """
-        if hasattr(field.rel.to._default_manager, 'get_by_natural_key'):
+        if hasattr(field.remote_field.model._default_manager, 'get_by_natural_key'):
             def m2m_convert(n):
                 keys = n.getElementsByTagName('natural')
                 if keys:
                     # If there are 'natural' subelements, it must be a natural key
                     field_value = [getInnerText(k).strip() for k in keys]
-                    obj_pk = field.rel.to._default_manager.db_manager(self.db).get_by_natural_key(*field_value).pk
+                    obj_pk = field.remote_field.model._default_manager.db_manager(self.db).get_by_natural_key(*field_value).pk
                 else:
                     # Otherwise, treat like a normal PK value.
-                    obj_pk = field.rel.to._meta.pk.to_python(n.getAttribute('pk'))
+                    obj_pk = field.remote_field.model._meta.pk.to_python(n.getAttribute('pk'))
                 return obj_pk
         else:
-            m2m_convert = lambda n: field.rel.to._meta.pk.to_python(n.getAttribute('pk'))
+            m2m_convert = lambda n: field.remote_field.model._meta.pk.to_python(n.getAttribute('pk'))
         return [m2m_convert(c) for c in node.getElementsByTagName("object")]
 
     def _get_model_from_node(self, node, attr):

+ 1 - 1
django/db/backends/base/introspection.py

@@ -125,7 +125,7 @@ class BaseDatabaseIntrospection(object):
                 for f in model._meta.local_many_to_many:
                     # If this is an m2m using an intermediate table,
                     # we don't need to reset the sequence.
-                    if f.rel.through is None:
+                    if f.remote_field.through is None:
                         sequence_list.append({'table': f.m2m_db_table(), 'column': None})
 
         return sequence_list

+ 34 - 34
django/db/backends/base/schema.py

@@ -241,9 +241,9 @@ class BaseDatabaseSchemaEditor(object):
                 definition += " %s" % col_type_suffix
             params.extend(extra_params)
             # FK
-            if field.rel and field.db_constraint:
-                to_table = field.rel.to._meta.db_table
-                to_column = field.rel.to._meta.get_field(field.rel.field_name).column
+            if field.remote_field and field.db_constraint:
+                to_table = field.remote_field.model._meta.db_table
+                to_column = field.remote_field.model._meta.get_field(field.remote_field.field_name).column
                 if self.connection.features.supports_foreign_keys:
                     self.deferred_sql.append(self._create_fk_sql(model, field, "_fk_%(to_table)s_%(to_column)s"))
                 elif self.sql_create_inline_fk:
@@ -284,8 +284,8 @@ class BaseDatabaseSchemaEditor(object):
 
         # Make M2M tables
         for field in model._meta.local_many_to_many:
-            if field.rel.through._meta.auto_created:
-                self.create_model(field.rel.through)
+            if field.remote_field.through._meta.auto_created:
+                self.create_model(field.remote_field.through)
 
     def delete_model(self, model):
         """
@@ -293,8 +293,8 @@ class BaseDatabaseSchemaEditor(object):
         """
         # Handle auto-created intermediary models
         for field in model._meta.local_many_to_many:
-            if field.rel.through._meta.auto_created:
-                self.delete_model(field.rel.through)
+            if field.remote_field.through._meta.auto_created:
+                self.delete_model(field.remote_field.through)
 
         # Delete the table
         self.execute(self.sql_delete_table % {
@@ -377,8 +377,8 @@ class BaseDatabaseSchemaEditor(object):
         table instead (for M2M fields)
         """
         # Special-case implicit M2M tables
-        if field.many_to_many and field.rel.through._meta.auto_created:
-            return self.create_model(field.rel.through)
+        if field.many_to_many and field.remote_field.through._meta.auto_created:
+            return self.create_model(field.remote_field.through)
         # Get the column's definition
         definition, params = self.column_sql(model, field, include_default=True)
         # It might not actually have a column behind it
@@ -409,7 +409,7 @@ class BaseDatabaseSchemaEditor(object):
         if field.db_index and not field.unique:
             self.deferred_sql.append(self._create_index_sql(model, [field]))
         # Add any FK constraints later
-        if field.rel and self.connection.features.supports_foreign_keys and field.db_constraint:
+        if field.remote_field and self.connection.features.supports_foreign_keys and field.db_constraint:
             self.deferred_sql.append(self._create_fk_sql(model, field, "_fk_%(to_table)s_%(to_column)s"))
         # Reset connection if required
         if self.connection.features.connection_persists_old_columns:
@@ -421,13 +421,13 @@ class BaseDatabaseSchemaEditor(object):
         but for M2Ms may involve deleting a table.
         """
         # Special-case implicit M2M tables
-        if field.many_to_many and field.rel.through._meta.auto_created:
-            return self.delete_model(field.rel.through)
+        if field.many_to_many and field.remote_field.through._meta.auto_created:
+            return self.delete_model(field.remote_field.through)
         # It might not actually have a column behind it
         if field.db_parameters(connection=self.connection)['type'] is None:
             return
         # Drop any FK constraints, MySQL requires explicit deletion
-        if field.rel:
+        if field.remote_field:
             fk_names = self._constraint_names(model, [field.column], foreign_key=True)
             for fk_name in fk_names:
                 self.execute(self._delete_constraint_sql(self.sql_delete_fk, model, fk_name))
@@ -454,21 +454,21 @@ class BaseDatabaseSchemaEditor(object):
         old_type = old_db_params['type']
         new_db_params = new_field.db_parameters(connection=self.connection)
         new_type = new_db_params['type']
-        if (old_type is None and old_field.rel is None) or (new_type is None and new_field.rel is None):
+        if (old_type is None and old_field.remote_field is None) or (new_type is None and new_field.remote_field is None):
             raise ValueError(
                 "Cannot alter field %s into %s - they do not properly define "
                 "db_type (are you using PostGIS 1.5 or badly-written custom "
                 "fields?)" % (old_field, new_field),
             )
         elif old_type is None and new_type is None and (
-                old_field.rel.through and new_field.rel.through and
-                old_field.rel.through._meta.auto_created and
-                new_field.rel.through._meta.auto_created):
+                old_field.remote_field.through and new_field.remote_field.through and
+                old_field.remote_field.through._meta.auto_created and
+                new_field.remote_field.through._meta.auto_created):
             return self._alter_many_to_many(model, old_field, new_field, strict)
         elif old_type is None and new_type is None and (
-                old_field.rel.through and new_field.rel.through and
-                not old_field.rel.through._meta.auto_created and
-                not new_field.rel.through._meta.auto_created):
+                old_field.remote_field.through and new_field.remote_field.through and
+                not old_field.remote_field.through._meta.auto_created and
+                not new_field.remote_field.through._meta.auto_created):
             # Both sides have through models; this is a no-op.
             return
         elif old_type is None or new_type is None:
@@ -487,7 +487,7 @@ class BaseDatabaseSchemaEditor(object):
 
         # Drop any FK constraints, we'll remake them later
         fks_dropped = set()
-        if old_field.rel and old_field.db_constraint:
+        if old_field.remote_field and old_field.db_constraint:
             fk_names = self._constraint_names(model, [old_field.column], foreign_key=True)
             if strict and len(fk_names) != 1:
                 raise ValueError("Found wrong number (%s) of foreign key constraints for %s.%s" % (
@@ -707,8 +707,8 @@ class BaseDatabaseSchemaEditor(object):
                 }
             )
         # Does it have a foreign key?
-        if (new_field.rel and
-                (fks_dropped or not old_field.rel or not old_field.db_constraint) and
+        if (new_field.remote_field and
+                (fks_dropped or not old_field.remote_field or not old_field.db_constraint) and
                 new_field.db_constraint):
             self.execute(self._create_fk_sql(model, new_field, "_fk_%(to_table)s_%(to_column)s"))
         # Rebuild FKs that pointed to us if we previously had to drop them
@@ -766,22 +766,22 @@ class BaseDatabaseSchemaEditor(object):
         Alters M2Ms to repoint their to= endpoints.
         """
         # Rename the through table
-        if old_field.rel.through._meta.db_table != new_field.rel.through._meta.db_table:
-            self.alter_db_table(old_field.rel.through, old_field.rel.through._meta.db_table,
-                                new_field.rel.through._meta.db_table)
+        if old_field.remote_field.through._meta.db_table != new_field.remote_field.through._meta.db_table:
+            self.alter_db_table(old_field.remote_field.through, old_field.remote_field.through._meta.db_table,
+                                new_field.remote_field.through._meta.db_table)
         # Repoint the FK to the other side
         self.alter_field(
-            new_field.rel.through,
+            new_field.remote_field.through,
             # We need the field that points to the target model, so we can tell alter_field to change it -
             # this is m2m_reverse_field_name() (as opposed to m2m_field_name, which points to our model)
-            old_field.rel.through._meta.get_field(old_field.m2m_reverse_field_name()),
-            new_field.rel.through._meta.get_field(new_field.m2m_reverse_field_name()),
+            old_field.remote_field.through._meta.get_field(old_field.m2m_reverse_field_name()),
+            new_field.remote_field.through._meta.get_field(new_field.m2m_reverse_field_name()),
         )
         self.alter_field(
-            new_field.rel.through,
+            new_field.remote_field.through,
             # for self-referential models we need to alter field from the other end too
-            old_field.rel.through._meta.get_field(old_field.m2m_field_name()),
-            new_field.rel.through._meta.get_field(new_field.m2m_field_name()),
+            old_field.remote_field.through._meta.get_field(old_field.m2m_field_name()),
+            new_field.remote_field.through._meta.get_field(new_field.m2m_field_name()),
         )
 
     def _create_index_name(self, model, column_names, suffix=""):
@@ -860,8 +860,8 @@ class BaseDatabaseSchemaEditor(object):
     def _create_fk_sql(self, model, field, suffix):
         from_table = model._meta.db_table
         from_column = field.column
-        to_table = field.related_field.model._meta.db_table
-        to_column = field.related_field.column
+        to_table = field.target_field.model._meta.db_table
+        to_column = field.target_field.column
         suffix = suffix % {
             "to_table": to_table,
             "to_column": to_column,

+ 1 - 1
django/db/backends/mysql/validation.py

@@ -14,7 +14,7 @@ class DatabaseValidation(BaseDatabaseValidation):
         errors = super(DatabaseValidation, self).check_field(field, **kwargs)
 
         # Ignore any related fields.
-        if getattr(field, 'rel', None) is None:
+        if getattr(field, 'remote_field', None) is None:
             field_type = field.db_type(connection)
 
             # Ignore any non-concrete fields

+ 1 - 1
django/db/backends/oracle/operations.py

@@ -346,7 +346,7 @@ WHEN (new.%(col_name)s IS NULL)
                     # continue to loop
                     break
             for f in model._meta.many_to_many:
-                if not f.rel.through:
+                if not f.remote_field.through:
                     table_name = self.quote_name(f.m2m_db_table())
                     sequence_name = self._get_sequence_name(f.m2m_db_table())
                     column_name = self.quote_name('id')

+ 1 - 1
django/db/backends/postgresql_psycopg2/operations.py

@@ -172,7 +172,7 @@ class DatabaseOperations(BaseDatabaseOperations):
                     )
                     break  # Only one AutoField is allowed per model, so don't bother continuing.
             for f in model._meta.many_to_many:
-                if not f.rel.through:
+                if not f.remote_field.through:
                     output.append(
                         "%s setval(pg_get_serial_sequence('%s','%s'), "
                         "coalesce(max(%s), 1), max(%s) %s null) %s %s;" % (

+ 14 - 14
django/db/backends/sqlite3/schema.py

@@ -118,8 +118,8 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
             del body[field.name]
             del mapping[field.column]
             # Remove any implicit M2M tables
-            if field.many_to_many and field.rel.through._meta.auto_created:
-                return self.delete_model(field.rel.through)
+            if field.many_to_many and field.remote_field.through._meta.auto_created:
+                return self.delete_model(field.remote_field.through)
         # Work inside a new app registry
         apps = Apps()
 
@@ -215,8 +215,8 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
         table instead (for M2M fields)
         """
         # Special-case implicit M2M tables
-        if field.many_to_many and field.rel.through._meta.auto_created:
-            return self.create_model(field.rel.through)
+        if field.many_to_many and field.remote_field.through._meta.auto_created:
+            return self.create_model(field.remote_field.through)
         self._remake_table(model, create_fields=[field])
 
     def remove_field(self, model, field):
@@ -227,8 +227,8 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
         # M2M fields are a special case
         if field.many_to_many:
             # For implicit M2M tables, delete the auto-created table
-            if field.rel.through._meta.auto_created:
-                self.delete_model(field.rel.through)
+            if field.remote_field.through._meta.auto_created:
+                self.delete_model(field.remote_field.through)
             # For explicit "through" M2M fields, do nothing
         # For everything else, remake.
         else:
@@ -263,25 +263,25 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
         """
         Alters M2Ms to repoint their to= endpoints.
         """
-        if old_field.rel.through._meta.db_table == new_field.rel.through._meta.db_table:
+        if old_field.remote_field.through._meta.db_table == new_field.remote_field.through._meta.db_table:
             # The field name didn't change, but some options did; we have to propagate this altering.
             self._remake_table(
-                old_field.rel.through,
+                old_field.remote_field.through,
                 alter_fields=[(
                     # We need the field that points to the target model, so we can tell alter_field to change it -
                     # this is m2m_reverse_field_name() (as opposed to m2m_field_name, which points to our model)
-                    old_field.rel.through._meta.get_field(old_field.m2m_reverse_field_name()),
-                    new_field.rel.through._meta.get_field(new_field.m2m_reverse_field_name()),
+                    old_field.remote_field.through._meta.get_field(old_field.m2m_reverse_field_name()),
+                    new_field.remote_field.through._meta.get_field(new_field.m2m_reverse_field_name()),
                 )],
                 override_uniques=(new_field.m2m_field_name(), new_field.m2m_reverse_field_name()),
             )
             return
 
         # Make a new through table
-        self.create_model(new_field.rel.through)
+        self.create_model(new_field.remote_field.through)
         # Copy the data across
         self.execute("INSERT INTO %s (%s) SELECT %s FROM %s" % (
-            self.quote_name(new_field.rel.through._meta.db_table),
+            self.quote_name(new_field.remote_field.through._meta.db_table),
             ', '.join([
                 "id",
                 new_field.m2m_column_name(),
@@ -292,7 +292,7 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
                 old_field.m2m_column_name(),
                 old_field.m2m_reverse_name(),
             ]),
-            self.quote_name(old_field.rel.through._meta.db_table),
+            self.quote_name(old_field.remote_field.through._meta.db_table),
         ))
         # Delete the old through table
-        self.delete_model(old_field.rel.through)
+        self.delete_model(old_field.remote_field.through)

+ 33 - 33
django/db/migrations/autodetector.py

@@ -78,7 +78,7 @@ class MigrationAutodetector(object):
         fields_def = []
         for name, field in fields:
             deconstruction = self.deep_deconstruct(field)
-            if field.rel and field.rel.to:
+            if field.remote_field and field.remote_field.model:
                 del deconstruction[2]['to']
             fields_def.append(deconstruction)
         return fields_def
@@ -163,11 +163,11 @@ class MigrationAutodetector(object):
             old_model_state = self.from_state.models[app_label, old_model_name]
             for field_name, field in old_model_state.fields:
                 old_field = self.old_apps.get_model(app_label, old_model_name)._meta.get_field(field_name)
-                if (hasattr(old_field, "rel") and getattr(old_field.rel, "through", None)
-                        and not old_field.rel.through._meta.auto_created):
+                if (hasattr(old_field, "remote_field") and getattr(old_field.remote_field, "through", None)
+                        and not old_field.remote_field.through._meta.auto_created):
                     through_key = (
-                        old_field.rel.through._meta.app_label,
-                        old_field.rel.through._meta.model_name,
+                        old_field.remote_field.through._meta.app_label,
+                        old_field.remote_field.through._meta.model_name,
                     )
                     self.through_users[through_key] = (app_label, old_model_name, field_name)
 
@@ -460,20 +460,20 @@ class MigrationAutodetector(object):
             related_fields = {}
             primary_key_rel = None
             for field in model_opts.local_fields:
-                if field.rel:
-                    if field.rel.to:
+                if field.remote_field:
+                    if field.remote_field.model:
                         if field.primary_key:
-                            primary_key_rel = field.rel.to
-                        elif not field.rel.parent_link:
+                            primary_key_rel = field.remote_field.model
+                        elif not field.remote_field.parent_link:
                             related_fields[field.name] = field
                     # through will be none on M2Ms on swapped-out models;
                     # we can treat lack of through as auto_created=True, though.
-                    if getattr(field.rel, "through", None) and not field.rel.through._meta.auto_created:
+                    if getattr(field.remote_field, "through", None) and not field.remote_field.through._meta.auto_created:
                         related_fields[field.name] = field
             for field in model_opts.local_many_to_many:
-                if field.rel.to:
+                if field.remote_field.model:
                     related_fields[field.name] = field
-                if getattr(field.rel, "through", None) and not field.rel.through._meta.auto_created:
+                if getattr(field.remote_field, "through", None) and not field.remote_field.through._meta.auto_created:
                     related_fields[field.name] = field
             # Are there unique/index_together to defer?
             unique_together = model_state.options.pop('unique_together', None)
@@ -522,13 +522,13 @@ class MigrationAutodetector(object):
                     dep_app_label = "__setting__"
                     dep_object_name = swappable_setting
                 else:
-                    dep_app_label = field.rel.to._meta.app_label
-                    dep_object_name = field.rel.to._meta.object_name
+                    dep_app_label = field.remote_field.model._meta.app_label
+                    dep_object_name = field.remote_field.model._meta.object_name
                 dependencies = [(dep_app_label, dep_object_name, None, True)]
-                if getattr(field.rel, "through", None) and not field.rel.through._meta.auto_created:
+                if getattr(field.remote_field, "through", None) and not field.remote_field.through._meta.auto_created:
                     dependencies.append((
-                        field.rel.through._meta.app_label,
-                        field.rel.through._meta.object_name,
+                        field.remote_field.through._meta.app_label,
+                        field.remote_field.through._meta.object_name,
                         None,
                         True
                     ))
@@ -639,17 +639,17 @@ class MigrationAutodetector(object):
             # Gather related fields
             related_fields = {}
             for field in model._meta.local_fields:
-                if field.rel:
-                    if field.rel.to:
+                if field.remote_field:
+                    if field.remote_field.model:
                         related_fields[field.name] = field
                     # through will be none on M2Ms on swapped-out models;
                     # we can treat lack of through as auto_created=True, though.
-                    if getattr(field.rel, "through", None) and not field.rel.through._meta.auto_created:
+                    if getattr(field.remote_field, "through", None) and not field.remote_field.through._meta.auto_created:
                         related_fields[field.name] = field
             for field in model._meta.local_many_to_many:
-                if field.rel.to:
+                if field.remote_field.model:
                     related_fields[field.name] = field
-                if getattr(field.rel, "through", None) and not field.rel.through._meta.auto_created:
+                if getattr(field.remote_field, "through", None) and not field.remote_field.through._meta.auto_created:
                     related_fields[field.name] = field
             # Generate option removal first
             unique_together = model_state.options.pop('unique_together', None)
@@ -736,7 +736,7 @@ class MigrationAutodetector(object):
             for rem_app_label, rem_model_name, rem_field_name in sorted(self.old_field_keys - self.new_field_keys):
                 if rem_app_label == app_label and rem_model_name == model_name:
                     old_field_dec = self.deep_deconstruct(old_model_state.get_field_by_name(rem_field_name))
-                    if field.rel and field.rel.to and 'to' in old_field_dec[2]:
+                    if field.remote_field and field.remote_field.model and 'to' in old_field_dec[2]:
                         old_rel_to = old_field_dec[2]['to']
                         if old_rel_to in self.renamed_models_rel:
                             old_field_dec[2]['to'] = self.renamed_models_rel[old_rel_to]
@@ -766,20 +766,20 @@ class MigrationAutodetector(object):
         field = self.new_apps.get_model(app_label, model_name)._meta.get_field(field_name)
         # Fields that are foreignkeys/m2ms depend on stuff
         dependencies = []
-        if field.rel and field.rel.to:
+        if field.remote_field and field.remote_field.model:
             # Account for FKs to swappable models
             swappable_setting = getattr(field, 'swappable_setting', None)
             if swappable_setting is not None:
                 dep_app_label = "__setting__"
                 dep_object_name = swappable_setting
             else:
-                dep_app_label = field.rel.to._meta.app_label
-                dep_object_name = field.rel.to._meta.object_name
+                dep_app_label = field.remote_field.model._meta.app_label
+                dep_object_name = field.remote_field.model._meta.object_name
             dependencies = [(dep_app_label, dep_object_name, None, True)]
-            if getattr(field.rel, "through", None) and not field.rel.through._meta.auto_created:
+            if getattr(field.remote_field, "through", None) and not field.remote_field.through._meta.auto_created:
                 dependencies.append((
-                    field.rel.through._meta.app_label,
-                    field.rel.through._meta.object_name,
+                    field.remote_field.through._meta.app_label,
+                    field.remote_field.through._meta.object_name,
                     None,
                     True,
                 ))
@@ -838,13 +838,13 @@ class MigrationAutodetector(object):
             new_field = self.new_apps.get_model(app_label, model_name)._meta.get_field(field_name)
             # Implement any model renames on relations; these are handled by RenameModel
             # so we need to exclude them from the comparison
-            if hasattr(new_field, "rel") and getattr(new_field.rel, "to", None):
+            if hasattr(new_field, "remote_field") and getattr(new_field.remote_field, "model", None):
                 rename_key = (
-                    new_field.rel.to._meta.app_label,
-                    new_field.rel.to._meta.model_name,
+                    new_field.remote_field.model._meta.app_label,
+                    new_field.remote_field.model._meta.model_name,
                 )
                 if rename_key in self.renamed_models:
-                    new_field.rel.to = old_field.rel.to
+                    new_field.remote_field.model = old_field.remote_field.model
             old_field_dec = self.deep_deconstruct(old_field)
             new_field_dec = self.deep_deconstruct(new_field)
             if old_field_dec != new_field_dec:

+ 5 - 5
django/db/migrations/operations/fields.py

@@ -191,11 +191,11 @@ class AlterField(Operation):
             # If the field is a relatedfield with an unresolved rel.to, just
             # set it equal to the other field side. Bandaid fix for AlterField
             # migrations that are part of a RenameModel change.
-            if from_field.rel and from_field.rel.to:
-                if isinstance(from_field.rel.to, six.string_types):
-                    from_field.rel.to = to_field.rel.to
-                elif to_field.rel and isinstance(to_field.rel.to, six.string_types):
-                    to_field.rel.to = from_field.rel.to
+            if from_field.remote_field and from_field.remote_field.model:
+                if isinstance(from_field.remote_field.model, six.string_types):
+                    from_field.remote_field.model = to_field.remote_field.model
+                elif to_field.remote_field and isinstance(to_field.remote_field.model, six.string_types):
+                    to_field.remote_field.model = from_field.remote_field.model
             if not self.preserve_default:
                 to_field.default = self.field.default
             schema_editor.alter_field(from_model, from_field, to_field)

+ 11 - 11
django/db/migrations/operations/models.py

@@ -74,9 +74,9 @@ class CreateModel(Operation):
                 strings_to_check.append(base.split(".")[-1])
         # Check we have no FKs/M2Ms with it
         for fname, field in self.fields:
-            if field.rel:
-                if isinstance(field.rel.to, six.string_types):
-                    strings_to_check.append(field.rel.to.split(".")[-1])
+            if field.remote_field:
+                if isinstance(field.remote_field.model, six.string_types):
+                    strings_to_check.append(field.remote_field.model.split(".")[-1])
         # Now go over all the strings and compare them
         for string in strings_to_check:
             if string.lower() == name.lower():
@@ -181,7 +181,7 @@ class RenameModel(Operation):
             for name, field in state.models[related_key].fields:
                 if name == related_object.field.name:
                     field = field.clone()
-                    field.rel.to = "%s.%s" % (app_label, self.new_name)
+                    field.remote_field.model = "%s.%s" % (app_label, self.new_name)
                 new_fields.append((name, field))
             state.models[related_key].fields = new_fields
             state.reload_model(*related_key)
@@ -220,11 +220,11 @@ class RenameModel(Operation):
             fields = zip(old_model._meta.local_many_to_many, new_model._meta.local_many_to_many)
             for (old_field, new_field) in fields:
                 # Skip self-referential fields as these are renamed above.
-                if new_field.model == new_field.related_model or not new_field.rel.through._meta.auto_created:
+                if new_field.model == new_field.related_model or not new_field.remote_field.through._meta.auto_created:
                     continue
                 # Rename the M2M table that's based on this model's name.
-                old_m2m_model = old_field.rel.through
-                new_m2m_model = new_field.rel.through
+                old_m2m_model = old_field.remote_field.through
+                new_m2m_model = new_field.remote_field.through
                 schema_editor.alter_db_table(
                     new_m2m_model,
                     old_m2m_model._meta.db_table,
@@ -296,11 +296,11 @@ class AlterModelTable(Operation):
             )
             # Rename M2M fields whose name is based on this model's db_table
             for (old_field, new_field) in zip(old_model._meta.local_many_to_many, new_model._meta.local_many_to_many):
-                if new_field.rel.through._meta.auto_created:
+                if new_field.remote_field.through._meta.auto_created:
                     schema_editor.alter_db_table(
-                        new_field.rel.through,
-                        old_field.rel.through._meta.db_table,
-                        new_field.rel.through._meta.db_table,
+                        new_field.remote_field.through,
+                        old_field.remote_field.through._meta.db_table,
+                        new_field.remote_field.through._meta.db_table,
                     )
 
     def database_backwards(self, app_label, schema_editor, from_state, to_state):

+ 4 - 4
django/db/migrations/optimizer.py

@@ -230,15 +230,15 @@ class MigrationOptimizer(object):
     def reduce_create_model_add_field(self, operation, other, in_between):
         if operation.name_lower == other.model_name_lower:
             # Don't allow optimizations of FKs through models they reference
-            if hasattr(other.field, "rel") and other.field.rel:
+            if hasattr(other.field, "remote_field") and other.field.remote_field:
                 for between in in_between:
                     # Check that it doesn't point to the model
-                    app_label, object_name = self.model_to_key(other.field.rel.to)
+                    app_label, object_name = self.model_to_key(other.field.remote_field.model)
                     if between.references_model(object_name, app_label):
                         return None
                     # Check that it's not through the model
-                    if getattr(other.field.rel, "through", None):
-                        app_label, object_name = self.model_to_key(other.field.rel.through)
+                    if getattr(other.field.remote_field, "through", None):
+                        app_label, object_name = self.model_to_key(other.field.remote_field.through)
                         if between.references_model(object_name, app_label):
                             return None
             # OK, that's fine

+ 3 - 3
django/db/migrations/state.py

@@ -94,9 +94,9 @@ class ProjectState(object):
             model_state = self.models[(app_label, model_name)]
             for name, field in model_state.fields:
                 if field.is_relation:
-                    if field.rel.to == RECURSIVE_RELATIONSHIP_CONSTANT:
+                    if field.remote_field.model == RECURSIVE_RELATIONSHIP_CONSTANT:
                         continue
-                    rel_app_label, rel_model_name = _get_app_label_and_model_name(field.rel.to, app_label)
+                    rel_app_label, rel_model_name = _get_app_label_and_model_name(field.remote_field.model, app_label)
                     related_models.add((rel_app_label, rel_model_name.lower()))
 
             # Unregister all related models
@@ -328,7 +328,7 @@ class ModelState(object):
         # Deconstruct the fields
         fields = []
         for field in model._meta.local_fields:
-            if getattr(field, "rel", None) and exclude_rels:
+            if getattr(field, "remote_field", None) and exclude_rels:
                 continue
             if isinstance(field, OrderWrt):
                 continue

+ 16 - 16
django/db/models/base.py

@@ -199,7 +199,7 @@ class ModelBase(type):
             # Locate OneToOneField instances.
             for field in base._meta.local_fields:
                 if isinstance(field, OneToOneField):
-                    parent_links[field.rel.to] = field
+                    parent_links[field.remote_field.model] = field
 
         # Do the appropriate setup for any model parents.
         for base in parents:
@@ -307,19 +307,19 @@ class ModelBase(type):
             # certain it has been created
             def make_foreign_order_accessors(field, model, cls):
                 setattr(
-                    field.rel.to,
+                    field.remote_field.model,
                     'get_%s_order' % cls.__name__.lower(),
                     curry(method_get_order, cls)
                 )
                 setattr(
-                    field.rel.to,
+                    field.remote_field.model,
                     'set_%s_order' % cls.__name__.lower(),
                     curry(method_set_order, cls)
                 )
             add_lazy_relation(
                 cls,
                 opts.order_with_respect_to,
-                opts.order_with_respect_to.rel.to,
+                opts.order_with_respect_to.remote_field.model,
                 make_foreign_order_accessors
             )
 
@@ -382,7 +382,7 @@ class Model(six.with_metaclass(ModelBase)):
                 setattr(self, field.attname, val)
                 kwargs.pop(field.name, None)
                 # Maintain compatibility with existing calls.
-                if isinstance(field.rel, ManyToOneRel):
+                if isinstance(field.remote_field, ManyToOneRel):
                     kwargs.pop(field.attname, None)
 
         # Now we're left with the unprocessed fields that *must* come from
@@ -399,7 +399,7 @@ class Model(six.with_metaclass(ModelBase)):
                 # This field will be populated on request.
                 continue
             if kwargs:
-                if isinstance(field.rel, ForeignObjectRel):
+                if isinstance(field.remote_field, ForeignObjectRel):
                     try:
                         # Assume object instance was passed in.
                         rel_obj = kwargs.pop(field.name)
@@ -879,7 +879,7 @@ class Model(six.with_metaclass(ModelBase)):
     def prepare_database_save(self, field):
         if self.pk is None:
             raise ValueError("Unsaved model instance %r cannot be used in an ORM query." % self)
-        return getattr(self, field.rel.field_name)
+        return getattr(self, field.remote_field.field_name)
 
     def clean(self):
         """
@@ -1238,20 +1238,20 @@ class Model(six.with_metaclass(ModelBase)):
         fields = cls._meta.local_many_to_many
 
         # Skip when the target model wasn't found.
-        fields = (f for f in fields if isinstance(f.rel.to, ModelBase))
+        fields = (f for f in fields if isinstance(f.remote_field.model, ModelBase))
 
         # Skip when the relationship model wasn't found.
-        fields = (f for f in fields if isinstance(f.rel.through, ModelBase))
+        fields = (f for f in fields if isinstance(f.remote_field.through, ModelBase))
 
         for f in fields:
-            signature = (f.rel.to, cls, f.rel.through)
+            signature = (f.remote_field.model, cls, f.remote_field.through)
             if signature in seen_intermediary_signatures:
                 errors.append(
                     checks.Error(
                         "The model has two many-to-many relations through "
                         "the intermediate model '%s.%s'." % (
-                            f.rel.through._meta.app_label,
-                            f.rel.through._meta.object_name
+                            f.remote_field.through._meta.app_label,
+                            f.remote_field.through._meta.object_name
                         ),
                         hint=None,
                         obj=cls,
@@ -1448,7 +1448,7 @@ class Model(six.with_metaclass(ModelBase)):
                     )
                 )
             else:
-                if isinstance(field.rel, models.ManyToManyRel):
+                if isinstance(field.remote_field, models.ManyToManyRel):
                     errors.append(
                         checks.Error(
                             "'%s' refers to a ManyToManyField '%s', but "
@@ -1595,7 +1595,7 @@ class Model(six.with_metaclass(ModelBase)):
         for f in cls._meta.local_many_to_many:
             # Check if auto-generated name for the M2M field is too long
             # for the database.
-            for m2m in f.rel.through._meta.local_fields:
+            for m2m in f.remote_field.through._meta.local_fields:
                 _, rel_name = m2m.get_attname_column()
                 if (m2m.db_column is None and rel_name is not None
                         and len(rel_name) > allowed_len):
@@ -1624,7 +1624,7 @@ class Model(six.with_metaclass(ModelBase)):
 def method_set_order(ordered_obj, self, id_list, using=None):
     if using is None:
         using = DEFAULT_DB_ALIAS
-    rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name)
+    rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.remote_field.field_name)
     order_name = ordered_obj._meta.order_with_respect_to.name
     # FIXME: It would be nice if there was an "update many" version of update
     # for situations like this.
@@ -1634,7 +1634,7 @@ def method_set_order(ordered_obj, self, id_list, using=None):
 
 
 def method_get_order(ordered_obj, self):
-    rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name)
+    rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.remote_field.field_name)
     order_name = ordered_obj._meta.order_with_respect_to.name
     pk_name = ordered_obj._meta.pk.name
     return [r[pk_name] for r in

+ 8 - 9
django/db/models/deletion.py

@@ -14,7 +14,7 @@ class ProtectedError(IntegrityError):
 
 
 def CASCADE(collector, field, sub_objs, using):
-    collector.collect(sub_objs, source=field.rel.to,
+    collector.collect(sub_objs, source=field.remote_field.model,
                       source_attr=field.name, nullable=field.null)
     if field.null and not connections[using].features.can_defer_constraint_checks:
         collector.add_field_update(field, None, sub_objs)
@@ -23,7 +23,7 @@ def CASCADE(collector, field, sub_objs, using):
 def PROTECT(collector, field, sub_objs, using):
     raise ProtectedError("Cannot delete some instances of model '%s' because "
         "they are referenced through a protected foreign key: '%s.%s'" % (
-            field.rel.to.__name__, sub_objs[0].__class__.__name__, field.name
+            field.remote_field.model.__name__, sub_objs[0].__class__.__name__, field.name
         ),
         sub_objs
     )
@@ -136,7 +136,7 @@ class Collector(object):
         skipping parent -> child -> parent chain preventing fast delete of
         the child.
         """
-        if from_field and from_field.rel.on_delete is not CASCADE:
+        if from_field and from_field.remote_field.on_delete is not CASCADE:
             return False
         if not (hasattr(objs, 'model') and hasattr(objs, '_raw_delete')):
             return False
@@ -153,7 +153,7 @@ class Collector(object):
         # Foreign keys pointing to this model, both from m2m and other
         # models.
         for related in get_candidate_relations_to_delete(opts):
-            if related.field.rel.on_delete is not DO_NOTHING:
+            if related.field.remote_field.on_delete is not DO_NOTHING:
                 return False
         for field in model._meta.virtual_fields:
             if hasattr(field, 'bulk_related_objects'):
@@ -214,14 +214,13 @@ class Collector(object):
                     # object instance.
                     parent_objs = [getattr(obj, ptr.name) for obj in new_objs]
                     self.collect(parent_objs, source=model,
-                                 source_attr=ptr.rel.related_name,
+                                 source_attr=ptr.remote_field.related_name,
                                  collect_related=False,
                                  reverse_dependency=True)
-
         if collect_related:
             for related in get_candidate_relations_to_delete(model._meta):
                 field = related.field
-                if field.rel.on_delete == DO_NOTHING:
+                if field.remote_field.on_delete == DO_NOTHING:
                     continue
                 batches = self.get_del_batches(new_objs, field)
                 for batch in batches:
@@ -229,14 +228,14 @@ class Collector(object):
                     if self.can_fast_delete(sub_objs, from_field=field):
                         self.fast_deletes.append(sub_objs)
                     elif sub_objs:
-                        field.rel.on_delete(self, field, sub_objs, self.using)
+                        field.remote_field.on_delete(self, field, sub_objs, self.using)
             for field in model._meta.virtual_fields:
                 if hasattr(field, 'bulk_related_objects'):
                     # Its something like generic foreign key.
                     sub_objs = field.bulk_related_objects(new_objs, self.using)
                     self.collect(sub_objs,
                                  source=model,
-                                 source_attr=field.rel.related_name,
+                                 source_attr=field.remote_field.related_name,
                                  nullable=True)
 
     def related_objects(self, related, objs):

+ 17 - 9
django/db/models/fields/__init__.py

@@ -23,6 +23,7 @@ from django.utils.duration import duration_string
 from django.utils.functional import cached_property, curry, total_ordering, Promise
 from django.utils.text import capfirst
 from django.utils import timezone
+from django.utils.deprecation import RemovedInDjango21Warning
 from django.utils.translation import ugettext_lazy as _
 from django.utils.encoding import (smart_text, force_text, force_bytes,
     python_2_unicode_compatible)
@@ -146,8 +147,8 @@ class Field(RegisterLookupMixin):
         self.primary_key = primary_key
         self.max_length, self._unique = max_length, unique
         self.blank, self.null = blank, null
-        self.rel = rel
-        self.is_relation = self.rel is not None
+        self.remote_field = rel
+        self.is_relation = self.remote_field is not None
         self.default = default
         self.editable = editable
         self.serialize = serialize
@@ -240,6 +241,13 @@ class Field(RegisterLookupMixin):
         else:
             return []
 
+    @property
+    def rel(self):
+        warnings.warn(
+            "Usage of field.rel has been deprecated. Use field.remote_field instead.",
+            RemovedInDjango21Warning, 2)
+        return self.remote_field
+
     def _check_choices(self):
         if self.choices:
             if (isinstance(self.choices, six.string_types) or
@@ -468,10 +476,10 @@ class Field(RegisterLookupMixin):
         # We don't have to deepcopy very much here, since most things are not
         # intended to be altered after initial creation.
         obj = copy.copy(self)
-        if self.rel:
-            obj.rel = copy.copy(self.rel)
-            if hasattr(self.rel, 'field') and self.rel.field is self:
-                obj.rel.field = obj
+        if self.remote_field:
+            obj.remote_field = copy.copy(self.remote_field)
+            if hasattr(self.remote_field, 'field') and self.remote_field.field is self:
+                obj.remote_field.field = obj
         memodict[id(self)] = obj
         return obj
 
@@ -811,10 +819,10 @@ class Field(RegisterLookupMixin):
                         not blank_defined else [])
         if self.choices:
             return first_choice + choices
-        rel_model = self.rel.to
+        rel_model = self.remote_field.model
         limit_choices_to = limit_choices_to or self.get_limit_choices_to()
-        if hasattr(self.rel, 'get_related_field'):
-            lst = [(getattr(x, self.rel.get_related_field().attname),
+        if hasattr(self.remote_field, 'get_related_field'):
+            lst = [(getattr(x, self.remote_field.get_related_field().attname),
                    smart_text(x))
                    for x in rel_model._default_manager.complex_filter(
                        limit_choices_to)]

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 220 - 190
django/db/models/fields/related.py


+ 2 - 2
django/db/models/fields/related_lookups.py

@@ -26,8 +26,8 @@ def get_normalized_value(value, lhs):
         # Account for one-to-one relations when sent a different model
         sources = lhs.output_field.get_path_info()[-1].target_fields
         for source in sources:
-            while not isinstance(value, source.model) and source.rel:
-                source = source.rel.to._meta.get_field(source.rel.field_name)
+            while not isinstance(value, source.model) and source.remote_field:
+                source = source.remote_field.model._meta.get_field(source.remote_field.field_name)
             value_list.append(getattr(value, source.attname))
         return tuple(value_list)
     if not isinstance(value, tuple):

+ 9 - 9
django/db/models/options.py

@@ -308,9 +308,9 @@ class Options(object):
         # ideally, we'd just ask for field.related_model. However, related_model
         # is a cached property, and all the models haven't been loaded yet, so
         # we need to make sure we don't cache a string reference.
-        if field.is_relation and hasattr(field.rel, 'to') and field.rel.to:
+        if field.is_relation and hasattr(field.remote_field, 'model') and field.remote_field.model:
             try:
-                field.rel.to._meta._expire_cache(forward=False)
+                field.remote_field.model._meta._expire_cache(forward=False)
             except AttributeError:
                 pass
             self._expire_cache()
@@ -393,7 +393,7 @@ class Options(object):
         is_not_an_m2m_field = lambda f: not (f.is_relation and f.many_to_many)
         is_not_a_generic_relation = lambda f: not (f.is_relation and f.one_to_many)
         is_not_a_generic_foreign_key = lambda f: not (
-            f.is_relation and f.many_to_one and not (hasattr(f.rel, 'to') and f.rel.to)
+            f.is_relation and f.many_to_one and not (hasattr(f.remote_field, 'model') and f.remote_field.model)
         )
         return make_immutable_fields_list(
             "fields",
@@ -592,8 +592,8 @@ class Options(object):
             children = chain.from_iterable(c._relation_tree
                                            for c in self.concrete_model._meta.proxied_children
                                            if c is not self)
-            relations = (f.rel for f in children
-                         if include_hidden or not f.rel.field.rel.is_hidden())
+            relations = (f.remote_field for f in children
+                         if include_hidden or not f.remote_field.field.remote_field.is_hidden())
             fields = chain(fields, relations)
         return list(fields)
 
@@ -690,8 +690,8 @@ class Options(object):
                 if f.is_relation and f.related_model is not None
             )
             for f in fields_with_relations:
-                if not isinstance(f.rel.to, six.string_types):
-                    related_objects_graph[f.rel.to._meta].append(f)
+                if not isinstance(f.remote_field.model, six.string_types):
+                    related_objects_graph[f.remote_field.model._meta].append(f)
 
         for model in all_models:
             # Set the relation_tree using the internal __dict__. In this way
@@ -804,8 +804,8 @@ class Options(object):
             for field in all_fields:
                 # If hidden fields should be included or the relation is not
                 # intentionally hidden, add to the fields dict.
-                if include_hidden or not field.rel.hidden:
-                    fields.append(field.rel)
+                if include_hidden or not field.remote_field.hidden:
+                    fields.append(field.remote_field)
 
         if forward:
             fields.extend(

+ 2 - 2
django/db/models/query.py

@@ -1645,12 +1645,12 @@ class RelatedPopulator(object):
         reverse = klass_info['reverse']
         self.reverse_cache_name = None
         if reverse:
-            self.cache_name = field.rel.get_cache_name()
+            self.cache_name = field.remote_field.get_cache_name()
             self.reverse_cache_name = field.get_cache_name()
         else:
             self.cache_name = field.get_cache_name()
             if field.unique:
-                self.reverse_cache_name = field.rel.get_cache_name()
+                self.reverse_cache_name = field.remote_field.get_cache_name()
 
     def get_deferred_cls(self, klass_info, init_list):
         model_cls = klass_info['model']

+ 2 - 2
django/db/models/query_utils.py

@@ -181,9 +181,9 @@ def select_related_descend(field, restricted, requested, load_fields, reverse=Fa
      * load_fields - the set of fields to be loaded on this model
      * reverse - boolean, True if we are checking a reverse select related
     """
-    if not field.rel:
+    if not field.remote_field:
         return False
-    if field.rel.parent_link and not reverse:
+    if field.remote_field.parent_link and not reverse:
         return False
     if restricted:
         if reverse and field.related_query_name() not in requested:

+ 4 - 4
django/db/models/sql/compiler.py

@@ -676,7 +676,7 @@ class SQLCompiler(object):
                                           only_load.get(field_model)):
                 continue
             klass_info = {
-                'model': f.rel.to,
+                'model': f.remote_field.model,
                 'field': f,
                 'reverse': False,
                 'from_parent': False,
@@ -686,13 +686,13 @@ class SQLCompiler(object):
             _, _, _, joins, _ = self.query.setup_joins(
                 [f.name], opts, root_alias)
             alias = joins[-1]
-            columns = self.get_default_columns(start_alias=alias, opts=f.rel.to._meta)
+            columns = self.get_default_columns(start_alias=alias, opts=f.remote_field.model._meta)
             for col in columns:
                 select_fields.append(len(select))
                 select.append((col, None))
             klass_info['select_fields'] = select_fields
             next_klass_infos = self.get_related_selections(
-                select, f.rel.to._meta, alias, cur_depth + 1, next, restricted)
+                select, f.remote_field.model._meta, alias, cur_depth + 1, next, restricted)
             get_related_klass_infos(klass_info, next_klass_infos)
 
         if restricted:
@@ -1003,7 +1003,7 @@ class SQLUpdateCompiler(SQLCompiler):
                 if val.contains_aggregate:
                     raise FieldError("Aggregate functions are not allowed in this query")
             elif hasattr(val, 'prepare_database_save'):
-                if field.rel:
+                if field.remote_field:
                     val = val.prepare_database_save(field)
                 else:
                     raise TypeError("Database is trying to update a relational field "

+ 2 - 2
django/db/models/sql/query.py

@@ -608,7 +608,7 @@ class Query(object):
                 if is_reverse_o2o(source):
                     cur_model = source.related_model
                 else:
-                    cur_model = source.rel.to
+                    cur_model = source.remote_field.model
                 opts = cur_model._meta
                 # Even if we're "just passing through" this model, we must add
                 # both the current model's pk and the related reference field
@@ -1303,7 +1303,7 @@ class Query(object):
                         opts = int_model._meta
                     else:
                         final_field = opts.parents[int_model]
-                        targets = (final_field.rel.get_related_field(),)
+                        targets = (final_field.remote_field.get_related_field(),)
                         opts = int_model._meta
                         path.append(PathInfo(final_field.model._meta, opts, targets, final_field, False, True))
                         cur_names_with_path[1].append(

+ 15 - 15
django/forms/models.py

@@ -589,8 +589,8 @@ class BaseModelFormSet(BaseFormSet):
         If the field is a related field, fetch the concrete field's (that
         is, the ultimate pointed-to field's) to_python.
         """
-        while field.rel is not None:
-            field = field.rel.get_related_field()
+        while field.remote_field is not None:
+            field = field.remote_field.get_related_field()
         return field.to_python
 
     def _construct_form(self, i, **kwargs):
@@ -797,7 +797,7 @@ class BaseModelFormSet(BaseFormSet):
 
         def pk_is_not_editable(pk):
             return ((not pk.editable) or (pk.auto_created or isinstance(pk, AutoField))
-                or (pk.rel and pk.rel.parent_link and pk_is_not_editable(pk.rel.to._meta.pk)))
+                or (pk.remote_field and pk.remote_field.parent_link and pk_is_not_editable(pk.remote_field.model._meta.pk)))
         if pk_is_not_editable(pk) or pk.name not in form.fields:
             if form.is_bound:
                 # If we're adding the related instance, ignore its primary key
@@ -813,7 +813,7 @@ class BaseModelFormSet(BaseFormSet):
                 except IndexError:
                     pk_value = None
             if isinstance(pk, OneToOneField) or isinstance(pk, ForeignKey):
-                qs = pk.rel.to._default_manager.get_queryset()
+                qs = pk.remote_field.model._default_manager.get_queryset()
             else:
                 qs = self.model._default_manager.get_queryset()
             qs = qs.using(form.instance._state.db)
@@ -863,7 +863,7 @@ class BaseInlineFormSet(BaseModelFormSet):
     def __init__(self, data=None, files=None, instance=None,
                  save_as_new=False, prefix=None, queryset=None, **kwargs):
         if instance is None:
-            self.instance = self.fk.rel.to()
+            self.instance = self.fk.remote_field.model()
         else:
             self.instance = instance
         self.save_as_new = save_as_new
@@ -893,15 +893,15 @@ class BaseInlineFormSet(BaseModelFormSet):
 
         # Set the fk value here so that the form can do its validation.
         fk_value = self.instance.pk
-        if self.fk.rel.field_name != self.fk.rel.to._meta.pk.name:
-            fk_value = getattr(self.instance, self.fk.rel.field_name)
+        if self.fk.remote_field.field_name != self.fk.remote_field.model._meta.pk.name:
+            fk_value = getattr(self.instance, self.fk.remote_field.field_name)
             fk_value = getattr(fk_value, 'pk', fk_value)
         setattr(form.instance, self.fk.get_attname(), fk_value)
         return form
 
     @classmethod
     def get_default_prefix(cls):
-        return cls.fk.rel.get_accessor_name(model=cls.model).replace('+', '')
+        return cls.fk.remote_field.get_accessor_name(model=cls.model).replace('+', '')
 
     def save_new(self, form, commit=True):
         # Ensure the latest copy of the related instance is present on each
@@ -911,7 +911,7 @@ class BaseInlineFormSet(BaseModelFormSet):
         # Use commit=False so we can assign the parent key afterwards, then
         # save the object.
         obj = form.save(commit=False)
-        pk_value = getattr(self.instance, self.fk.rel.field_name)
+        pk_value = getattr(self.instance, self.fk.remote_field.field_name)
         setattr(obj, self.fk.get_attname(), getattr(pk_value, 'pk', pk_value))
         if commit:
             obj.save()
@@ -932,8 +932,8 @@ class BaseInlineFormSet(BaseModelFormSet):
             kwargs = {
                 'label': getattr(form.fields.get(name), 'label', capfirst(self.fk.verbose_name))
             }
-            if self.fk.rel.field_name != self.fk.rel.to._meta.pk.name:
-                kwargs['to_field'] = self.fk.rel.field_name
+            if self.fk.remote_field.field_name != self.fk.remote_field.model._meta.pk.name:
+                kwargs['to_field'] = self.fk.remote_field.field_name
 
         # If we're adding a new object, ignore a parent's auto-generated pk
         # as it will be regenerated on the save request.
@@ -970,8 +970,8 @@ def _get_foreign_key(parent_model, model, fk_name=None, can_fail=False):
         if len(fks_to_parent) == 1:
             fk = fks_to_parent[0]
             if not isinstance(fk, ForeignKey) or \
-                    (fk.rel.to != parent_model and
-                     fk.rel.to not in parent_model._meta.get_parent_list()):
+                    (fk.remote_field.model != parent_model and
+                     fk.remote_field.model not in parent_model._meta.get_parent_list()):
                 raise ValueError(
                     "fk_name '%s' is not a ForeignKey to '%s.%s'."
                     % (fk_name, parent_model._meta.app_label, parent_model._meta.object_name))
@@ -984,8 +984,8 @@ def _get_foreign_key(parent_model, model, fk_name=None, can_fail=False):
         fks_to_parent = [
             f for f in opts.fields
             if isinstance(f, ForeignKey)
-            and (f.rel.to == parent_model
-                or f.rel.to in parent_model._meta.get_parent_list())
+            and (f.remote_field.model == parent_model
+                or f.remote_field.model in parent_model._meta.get_parent_list())
         ]
         if len(fks_to_parent) == 1:
             fk = fks_to_parent[0]

+ 4 - 0
docs/internals/deprecation.txt

@@ -26,6 +26,10 @@ details on these changes.
   compatibility layer which allows absolute URLs to be considered equal to
   relative ones when the path is identical will also be removed.
 
+* ``Field.rel`` will be removed.
+
+* ``Field.remote_field.to`` attribute will be removed.
+
 .. _deprecation-removed-in-2.0:
 
 2.0

+ 9 - 0
docs/releases/1.9.txt

@@ -348,6 +348,15 @@ versions:
 Its parsing caused bugs with the current syntax, so support for the old syntax
 will be removed in Django 2.0 following an accelerated deprecation.
 
+``Field.rel`` changes
+~~~~~~~~~~~~~~~~~~~~~
+
+``Field.rel`` and its methods and attributes have changed to match the related
+fields API. The ``Field.rel`` attribute is renamed to ``remote_field`` and many
+of its methods and attributes are either changed or renamed.
+
+The aim of these changes is to provide a documented API for relation fields.
+
 Miscellaneous
 ~~~~~~~~~~~~~
 

+ 10 - 10
tests/admin_widgets/tests.py

@@ -437,7 +437,7 @@ class ForeignKeyRawIdWidgetTest(DjangoTestCase):
         band.album_set.create(
             name='Hybrid Theory', cover_art=r'albums\hybrid_theory.jpg'
         )
-        rel = models.Album._meta.get_field('band').rel
+        rel = models.Album._meta.get_field('band').remote_field
 
         w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
         self.assertHTMLEqual(
@@ -456,7 +456,7 @@ class ForeignKeyRawIdWidgetTest(DjangoTestCase):
         core = models.Inventory.objects.create(
             barcode=87, name='Core', parent=apple
         )
-        rel = models.Inventory._meta.get_field('parent').rel
+        rel = models.Inventory._meta.get_field('parent').remote_field
         w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
         self.assertHTMLEqual(
             w.render('test', core.parent_id, attrs={}), (
@@ -471,7 +471,7 @@ class ForeignKeyRawIdWidgetTest(DjangoTestCase):
         # have no magnifying glass link. See #16542
         big_honeycomb = models.Honeycomb.objects.create(location='Old tree')
         big_honeycomb.bee_set.create()
-        rel = models.Bee._meta.get_field('honeycomb').rel
+        rel = models.Bee._meta.get_field('honeycomb').remote_field
 
         w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
         self.assertHTMLEqual(
@@ -484,7 +484,7 @@ class ForeignKeyRawIdWidgetTest(DjangoTestCase):
         # no magnifying glass link. See #16542
         subject1 = models.Individual.objects.create(name='Subject #1')
         models.Individual.objects.create(name='Child', parent=subject1)
-        rel = models.Individual._meta.get_field('parent').rel
+        rel = models.Individual._meta.get_field('parent').remote_field
 
         w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
         self.assertHTMLEqual(
@@ -494,7 +494,7 @@ class ForeignKeyRawIdWidgetTest(DjangoTestCase):
 
     def test_proper_manager_for_label_lookup(self):
         # see #9258
-        rel = models.Inventory._meta.get_field('parent').rel
+        rel = models.Inventory._meta.get_field('parent').remote_field
         w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site)
 
         hidden = models.Inventory.objects.create(
@@ -521,7 +521,7 @@ class ManyToManyRawIdWidgetTest(DjangoTestCase):
         m1 = models.Member.objects.create(name='Chester')
         m2 = models.Member.objects.create(name='Mike')
         band.members.add(m1, m2)
-        rel = models.Band._meta.get_field('members').rel
+        rel = models.Band._meta.get_field('members').remote_field
 
         w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site)
         self.assertHTMLEqual(
@@ -546,7 +546,7 @@ class ManyToManyRawIdWidgetTest(DjangoTestCase):
         c1 = models.Company.objects.create(name='Doodle')
         c2 = models.Company.objects.create(name='Pear')
         consultor1.companies.add(c1, c2)
-        rel = models.Advisor._meta.get_field('companies').rel
+        rel = models.Advisor._meta.get_field('companies').remote_field
 
         w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site)
         self.assertHTMLEqual(
@@ -562,14 +562,14 @@ class ManyToManyRawIdWidgetTest(DjangoTestCase):
 
 class RelatedFieldWidgetWrapperTests(DjangoTestCase):
     def test_no_can_add_related(self):
-        rel = models.Individual._meta.get_field('parent').rel
+        rel = models.Individual._meta.get_field('parent').remote_field
         w = widgets.AdminRadioSelect()
         # Used to fail with a name error.
         w = widgets.RelatedFieldWidgetWrapper(w, rel, widget_admin_site)
         self.assertFalse(w.can_add_related)
 
     def test_select_multiple_widget_cant_change_delete_related(self):
-        rel = models.Individual._meta.get_field('parent').rel
+        rel = models.Individual._meta.get_field('parent').remote_field
         widget = forms.SelectMultiple()
         wrapper = widgets.RelatedFieldWidgetWrapper(
             widget, rel, widget_admin_site,
@@ -582,7 +582,7 @@ class RelatedFieldWidgetWrapperTests(DjangoTestCase):
         self.assertFalse(wrapper.can_delete_related)
 
     def test_on_delete_cascade_rel_cant_delete_related(self):
-        rel = models.Individual._meta.get_field('soulmate').rel
+        rel = models.Individual._meta.get_field('soulmate').remote_field
         widget = forms.Select()
         wrapper = widgets.RelatedFieldWidgetWrapper(
             widget, rel, widget_admin_site,

+ 1 - 1
tests/backends/tests.py

@@ -1058,7 +1058,7 @@ class DBConstraintTestCase(TestCase):
         self.assertEqual(models.Object.objects.count(), 2)
         self.assertEqual(obj.related_objects.count(), 1)
 
-        intermediary_model = models.Object._meta.get_field("related_objects").rel.through
+        intermediary_model = models.Object._meta.get_field("related_objects").remote_field.through
         intermediary_model.objects.create(from_object_id=obj.id, to_object_id=12345)
         self.assertEqual(obj.related_objects.count(), 1)
         self.assertEqual(intermediary_model.objects.count(), 2)

+ 1 - 1
tests/basic/tests.py

@@ -766,5 +766,5 @@ class TestRelatedObjectDeprecation(TestCase):
             self.assertEqual(len(warns), 1)
             self.assertEqual(
                 str(warns.pop().message),
-                'Usage of field.related has been deprecated. Use field.rel instead.'
+                'Usage of field.related has been deprecated. Use field.remote_field instead.'
             )

+ 1 - 1
tests/delete/tests.py

@@ -153,7 +153,7 @@ class DeletionTests(TestCase):
         r = R.objects.create()
         m.m2m.add(r)
         r.delete()
-        through = M._meta.get_field('m2m').rel.through
+        through = M._meta.get_field('m2m').remote_field.through
         self.assertFalse(through.objects.exists())
 
         r = R.objects.create()

+ 2 - 2
tests/field_deconstruction/tests.py

@@ -178,8 +178,8 @@ class FieldDeconstructionTests(TestCase):
         # Test basic pointing
         from django.contrib.auth.models import Permission
         field = models.ForeignKey("auth.Permission")
-        field.rel.to = Permission
-        field.rel.field_name = "id"
+        field.remote_field.model = Permission
+        field.remote_field.field_name = "id"
         name, path, args, kwargs = field.deconstruct()
         self.assertEqual(path, "django.db.models.ForeignKey")
         self.assertEqual(args, [])

+ 1 - 1
tests/foreign_object/models.py

@@ -109,7 +109,7 @@ class ArticleTranslationDescriptor(ReverseSingleRelatedObjectDescriptor):
         if instance is None:
             raise AttributeError("%s must be accessed via instance" % self.field.name)
         setattr(instance, self.cache_name, value)
-        if value is not None and not self.field.rel.multiple:
+        if value is not None and not self.field.remote_field.multiple:
             setattr(value, self.field.related.get_cache_name(), instance)
 
 

+ 3 - 3
tests/many_to_one/tests.py

@@ -565,12 +565,12 @@ class ManyToOneTests(TestCase):
         p = Parent()
         with self.assertRaisesMessage(ValueError,
                 'Cannot assign "%r": "%s" instance isn\'t saved in the database.'
-                % (p, Child.parent.field.rel.to._meta.object_name)):
+                % (p, Child.parent.field.remote_field.model._meta.object_name)):
             Child(parent=p)
 
         with self.assertRaisesMessage(ValueError,
                 'Cannot assign "%r": "%s" instance isn\'t saved in the database.'
-                % (p, Child.parent.field.rel.to._meta.object_name)):
+                % (p, Child.parent.field.remote_field.model._meta.object_name)):
             ToFieldChild(parent=p)
 
         # Creation using attname keyword argument and an id will cause the
@@ -610,7 +610,7 @@ class ManyToOneTests(TestCase):
         # Regression for #12190 -- Should be able to instantiate a FK outside
         # of a model, and interrogate its related field.
         cat = models.ForeignKey(Category)
-        self.assertEqual('id', cat.rel.get_related_field().name)
+        self.assertEqual('id', cat.remote_field.get_related_field().name)
 
     def test_relation_unsaved(self):
         # Test that the <field>_set manager does not join on Null value fields (#17541)

+ 5 - 5
tests/migrations/test_autodetector.py

@@ -1068,7 +1068,7 @@ class AutodetectorTests(TestCase):
         autodetector = MigrationAutodetector(before, after)
         changes = autodetector._detect_changes()
         # The field name the FK on the book model points to
-        self.assertEqual(changes['otherapp'][0].operations[0].fields[2][1].rel.field_name, 'id')
+        self.assertEqual(changes['otherapp'][0].operations[0].fields[2][1].remote_field.field_name, 'id')
 
         # Now, we test the custom pk field name
         before = self.make_project_state([])
@@ -1076,7 +1076,7 @@ class AutodetectorTests(TestCase):
         autodetector = MigrationAutodetector(before, after)
         changes = autodetector._detect_changes()
         # The field name the FK on the book model points to
-        self.assertEqual(changes['otherapp'][0].operations[0].fields[2][1].rel.field_name, 'pk_field')
+        self.assertEqual(changes['otherapp'][0].operations[0].fields[2][1].remote_field.field_name, 'pk_field')
 
     def test_unmanaged_create(self):
         """Tests that the autodetector correctly deals with managed models."""
@@ -1126,7 +1126,7 @@ class AutodetectorTests(TestCase):
         autodetector = MigrationAutodetector(before, after)
         changes = autodetector._detect_changes()
         # The field name the FK on the book model points to
-        self.assertEqual(changes['otherapp'][0].operations[0].fields[2][1].rel.field_name, 'id')
+        self.assertEqual(changes['otherapp'][0].operations[0].fields[2][1].remote_field.field_name, 'id')
 
         # Now, we test the custom pk field name
         before = self.make_project_state([])
@@ -1134,7 +1134,7 @@ class AutodetectorTests(TestCase):
         autodetector = MigrationAutodetector(before, after)
         changes = autodetector._detect_changes()
         # The field name the FK on the book model points to
-        self.assertEqual(changes['otherapp'][0].operations[0].fields[2][1].rel.field_name, 'pk_field')
+        self.assertEqual(changes['otherapp'][0].operations[0].fields[2][1].remote_field.field_name, 'pk_field')
 
     @override_settings(AUTH_USER_MODEL="thirdapp.CustomUser")
     def test_swappable(self):
@@ -1159,7 +1159,7 @@ class AutodetectorTests(TestCase):
         self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"])
         self.assertOperationAttributes(changes, 'testapp', 0, 0, model_name="author", name='user')
         fk_field = changes['testapp'][0].operations[0].field
-        to_model = '%s.%s' % (fk_field.rel.to._meta.app_label, fk_field.rel.to._meta.object_name)
+        to_model = '%s.%s' % (fk_field.remote_field.model._meta.app_label, fk_field.remote_field.model._meta.object_name)
         self.assertEqual(to_model, 'thirdapp.CustomUser')
 
     def test_add_field_with_default(self):

+ 6 - 6
tests/migrations/test_operations.py

@@ -479,7 +479,7 @@ class OperationTests(OperationTestBase):
         self.assertNotIn(("test_rnmo", "pony"), new_state.models)
         self.assertIn(("test_rnmo", "horse"), new_state.models)
         # RenameModel also repoints all incoming FKs and M2Ms
-        self.assertEqual("test_rnmo.Horse", new_state.models["test_rnmo", "rider"].fields[1][1].rel.to)
+        self.assertEqual("test_rnmo.Horse", new_state.models["test_rnmo", "rider"].fields[1][1].remote_field.model)
         self.assertTableNotExists("test_rnmo_pony")
         self.assertTableExists("test_rnmo_horse")
         if connection.features.supports_foreign_keys:
@@ -490,7 +490,7 @@ class OperationTests(OperationTestBase):
         # Test original state and database
         self.assertIn(("test_rnmo", "pony"), original_state.models)
         self.assertNotIn(("test_rnmo", "horse"), original_state.models)
-        self.assertEqual("Pony", original_state.models["test_rnmo", "rider"].fields[1][1].rel.to)
+        self.assertEqual("Pony", original_state.models["test_rnmo", "rider"].fields[1][1].remote_field.model)
         self.assertTableExists("test_rnmo_pony")
         self.assertTableNotExists("test_rnmo_horse")
         if connection.features.supports_foreign_keys:
@@ -515,7 +515,7 @@ class OperationTests(OperationTestBase):
         self.assertNotIn(("test_rmwsrf", "rider"), new_state.models)
         self.assertIn(("test_rmwsrf", "horserider"), new_state.models)
         # Remember, RenameModel also repoints all incoming FKs and M2Ms
-        self.assertEqual("test_rmwsrf.HorseRider", new_state.models["test_rmwsrf", "horserider"].fields[2][1].rel.to)
+        self.assertEqual("test_rmwsrf.HorseRider", new_state.models["test_rmwsrf", "horserider"].fields[2][1].remote_field.model)
         # Test the database alteration
         self.assertTableExists("test_rmwsrf_rider")
         self.assertTableNotExists("test_rmwsrf_horserider")
@@ -553,8 +553,8 @@ class OperationTests(OperationTestBase):
         self.assertIn(("test_rmwsc", "littlehorse"), new_state.models)
         # RenameModel shouldn't repoint the superclass's relations, only local ones
         self.assertEqual(
-            project_state.models["test_rmwsc", "rider"].fields[1][1].rel.to,
-            new_state.models["test_rmwsc", "rider"].fields[1][1].rel.to
+            project_state.models["test_rmwsc", "rider"].fields[1][1].remote_field.model,
+            new_state.models["test_rmwsc", "rider"].fields[1][1].remote_field.model
         )
         # Before running the migration we have a table for Shetland Pony, not Little Horse
         self.assertTableExists("test_rmwsc_shetlandpony")
@@ -612,7 +612,7 @@ class OperationTests(OperationTestBase):
         pony.riders.add(rider)
         self.assertEqual(Pony.objects.count(), 2)
         self.assertEqual(Rider.objects.count(), 2)
-        self.assertEqual(Pony._meta.get_field('riders').rel.through.objects.count(), 2)
+        self.assertEqual(Pony._meta.get_field('riders').remote_field.through.objects.count(), 2)
 
     def test_add_field(self):
         """

+ 3 - 3
tests/model_fields/test_field_flags.py

@@ -155,7 +155,7 @@ class FieldFlagsTests(test.TestCase):
 
         # Ensure all m2m reverses are m2m
         for field in m2m_type_fields:
-            reverse_field = field.rel
+            reverse_field = field.remote_field
             self.assertTrue(reverse_field.is_relation)
             self.assertTrue(reverse_field.many_to_many)
             self.assertTrue(reverse_field.related_model)
@@ -171,7 +171,7 @@ class FieldFlagsTests(test.TestCase):
         # Ensure all o2m reverses are m2o
         for field in o2m_type_fields:
             if field.concrete:
-                reverse_field = field.rel
+                reverse_field = field.remote_field
                 self.assertTrue(reverse_field.is_relation and reverse_field.many_to_one)
 
     def test_cardinality_m2o(self):
@@ -213,6 +213,6 @@ class FieldFlagsTests(test.TestCase):
         for field in AllFieldsModel._meta.get_fields():
             is_concrete_forward_field = field.concrete and field.related_model
             if is_concrete_forward_field:
-                reverse_field = field.rel
+                reverse_field = field.remote_field
                 self.assertEqual(field.model, reverse_field.related_model)
                 self.assertEqual(field.related_model, reverse_field.model)

+ 1 - 1
tests/model_fields/tests.py

@@ -199,7 +199,7 @@ class ForeignKeyTests(test.TestCase):
         self.assertEqual(warnings, expected_warnings)
 
     def test_related_name_converted_to_text(self):
-        rel_name = Bar._meta.get_field('a').rel.related_name
+        rel_name = Bar._meta.get_field('a').remote_field.related_name
         self.assertIsInstance(rel_name, six.text_type)
 
     def test_abstract_model_pending_lookups(self):

+ 1 - 1
tests/model_meta/tests.py

@@ -226,7 +226,7 @@ class RelationTreeTests(TestCase):
         # Testing non hidden related objects
         self.assertEqual(
             sorted([field.related_query_name() for field in Relation._meta._relation_tree
-                   if not field.rel.field.rel.is_hidden()]),
+                   if not field.remote_field.field.remote_field.is_hidden()]),
             sorted([
                 'fk_abstract_rel', 'fk_base_rel', 'fk_concrete_rel', 'fo_abstract_rel',
                 'fo_base_rel', 'fo_concrete_rel', 'm2m_abstract_rel',

+ 2 - 2
tests/model_options/models/tablespaces.py

@@ -42,8 +42,8 @@ class Article(models.Model):
 
 # Also set the tables for automatically created models
 
-Authors = Article._meta.get_field('authors').rel.through
+Authors = Article._meta.get_field('authors').remote_field.through
 Authors._meta.db_table = 'model_options_articleref_authors'
 
-Reviewers = Article._meta.get_field('reviewers').rel.through
+Reviewers = Article._meta.get_field('reviewers').remote_field.through
 Reviewers._meta.db_table = 'model_options_articleref_reviewers'

+ 2 - 2
tests/one_to_one/tests.py

@@ -136,7 +136,7 @@ class OneToOneTests(TestCase):
         place = Place(name='User', address='London')
         with self.assertRaisesMessage(ValueError,
                             'Cannot assign "%r": "%s" instance isn\'t saved in the database.'
-                            % (place, Restaurant.place.field.rel.to._meta.object_name)):
+                            % (place, Restaurant.place.field.remote_field.model._meta.object_name)):
             Restaurant.objects.create(place=place, serves_hot_dogs=True, serves_pizza=False)
         bar = UndergroundBar()
         p = Place(name='User', address='London')
@@ -410,7 +410,7 @@ class OneToOneTests(TestCase):
         be added to the related model.
         """
         self.assertFalse(
-            hasattr(Target, HiddenPointer._meta.get_field('target').rel.get_accessor_name())
+            hasattr(Target, HiddenPointer._meta.get_field('target').remote_field.get_accessor_name())
         )
 
     def test_related_object(self):

+ 1 - 1
tests/queryset_pickle/tests.py

@@ -82,7 +82,7 @@ class PickleabilityTestCase(TestCase):
         m1 = M2MModel.objects.create()
         g1 = Group.objects.create(name='foof')
         m1.groups.add(g1)
-        m2m_through = M2MModel._meta.get_field('groups').rel.through
+        m2m_through = M2MModel._meta.get_field('groups').remote_field.through
         original = m2m_through.objects.get()
         dumped = pickle.dumps(original)
         reloaded = pickle.loads(dumped)

+ 6 - 5
tests/schema/fields.py

@@ -35,12 +35,13 @@ class CustomManyToManyField(RelatedField):
         super(CustomManyToManyField, self).__init__(**kwargs)
 
     def contribute_to_class(self, cls, name, **kwargs):
-        if self.rel.symmetrical and (self.rel.to == "self" or self.rel.to == cls._meta.object_name):
-            self.rel.related_name = "%s_rel_+" % name
+        if self.remote_field.symmetrical and (
+                self.remote_field.model == "self" or self.remote_field.model == cls._meta.object_name):
+            self.remote_field.related_name = "%s_rel_+" % name
         super(CustomManyToManyField, self).contribute_to_class(cls, name, **kwargs)
-        if not self.rel.through and not cls._meta.abstract and not cls._meta.swapped:
-            self.rel.through = create_many_to_many_intermediary_model(self, cls)
-        setattr(cls, self.name, ManyRelatedObjectsDescriptor(self.rel))
+        if not self.remote_field.through and not cls._meta.abstract and not cls._meta.swapped:
+            self.remote_field.through = create_many_to_many_intermediary_model(self, cls)
+        setattr(cls, self.name, ManyRelatedObjectsDescriptor(self.remote_field))
         self.m2m_db_table = curry(self._get_m2m_db_table, cls._meta)
 
     def get_internal_type(self):

+ 9 - 9
tests/schema/tests.py

@@ -68,7 +68,7 @@ class SchemaTests(TransactionTestCase):
                 # Remove any M2M tables first
                 for field in model._meta.local_many_to_many:
                     with atomic():
-                        tbl = field.rel.through._meta.db_table
+                        tbl = field.remote_field.through._meta.db_table
                         if tbl in table_names:
                             cursor.execute(connection.schema_editor().sql_delete_table % {
                                 "table": connection.ops.quote_name(tbl),
@@ -244,7 +244,7 @@ class SchemaTests(TransactionTestCase):
         with connection.schema_editor() as editor:
             editor.add_field(LocalAuthorWithM2M, new_field)
         # Make sure no FK constraint is present
-        constraints = self.get_constraints(new_field.rel.through._meta.db_table)
+        constraints = self.get_constraints(new_field.remote_field.through._meta.db_table)
         for name, details in constraints.items():
             if details['columns'] == ["tag_id"] and details['foreign_key']:
                 self.fail("FK constraint for tag_id found")
@@ -740,7 +740,7 @@ class SchemaTests(TransactionTestCase):
             editor.create_model(TagM2MTest)
             editor.create_model(LocalBookWithM2M)
         # Ensure there is now an m2m table there
-        columns = self.column_classes(LocalBookWithM2M._meta.get_field("tags").rel.through)
+        columns = self.column_classes(LocalBookWithM2M._meta.get_field("tags").remote_field.through)
         self.assertEqual(columns['tagm2mtest_id'][0], "IntegerField")
 
     def test_m2m_create(self):
@@ -813,12 +813,12 @@ class SchemaTests(TransactionTestCase):
         new_field = M2MFieldClass("schema.TagM2MTest", related_name="authors")
         new_field.contribute_to_class(LocalAuthorWithM2M, "tags")
         # Ensure there's no m2m table there
-        self.assertRaises(DatabaseError, self.column_classes, new_field.rel.through)
+        self.assertRaises(DatabaseError, self.column_classes, new_field.remote_field.through)
         # Add the field
         with connection.schema_editor() as editor:
             editor.add_field(LocalAuthorWithM2M, new_field)
         # Ensure there is now an m2m table there
-        columns = self.column_classes(new_field.rel.through)
+        columns = self.column_classes(new_field.remote_field.through)
         self.assertEqual(columns['tagm2mtest_id'][0], "IntegerField")
 
         # "Alter" the field. This should not rename the DB table to itself.
@@ -829,7 +829,7 @@ class SchemaTests(TransactionTestCase):
         with connection.schema_editor() as editor:
             editor.remove_field(LocalAuthorWithM2M, new_field)
         # Ensure there's no m2m table there
-        self.assertRaises(DatabaseError, self.column_classes, new_field.rel.through)
+        self.assertRaises(DatabaseError, self.column_classes, new_field.remote_field.through)
 
     def test_m2m(self):
         self._test_m2m(ManyToManyField)
@@ -910,7 +910,7 @@ class SchemaTests(TransactionTestCase):
             editor.create_model(TagM2MTest)
             editor.create_model(UniqueTest)
         # Ensure the M2M exists and points to TagM2MTest
-        constraints = self.get_constraints(LocalBookWithM2M._meta.get_field("tags").rel.through._meta.db_table)
+        constraints = self.get_constraints(LocalBookWithM2M._meta.get_field("tags").remote_field.through._meta.db_table)
         if connection.features.supports_foreign_keys:
             for name, details in constraints.items():
                 if details['columns'] == ["tagm2mtest_id"] and details['foreign_key']:
@@ -925,9 +925,9 @@ class SchemaTests(TransactionTestCase):
         with connection.schema_editor() as editor:
             editor.alter_field(LocalBookWithM2M, old_field, new_field)
         # Ensure old M2M is gone
-        self.assertRaises(DatabaseError, self.column_classes, LocalBookWithM2M._meta.get_field("tags").rel.through)
+        self.assertRaises(DatabaseError, self.column_classes, LocalBookWithM2M._meta.get_field("tags").remote_field.through)
         # Ensure the new M2M exists and points to UniqueTest
-        constraints = self.get_constraints(new_field.rel.through._meta.db_table)
+        constraints = self.get_constraints(new_field.remote_field.through._meta.db_table)
         if connection.features.supports_foreign_keys:
             for name, details in constraints.items():
                 if details['columns'] == ["uniquetest_id"] and details['foreign_key']:

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio