From ddd3268975dca9094d94ab1df56dae0a24a58865 Mon Sep 17 00:00:00 2001 From: Tim Graham Date: Fri, 30 Dec 2016 17:50:05 -0500 Subject: [PATCH] Refs #21127 -- Required on_delete for ForeignKey/OneToOneField. Per deprecation timeline. --- django/db/models/fields/related.py | 53 +---------- docs/ref/models/fields.txt | 5 -- docs/releases/2.0.txt | 3 + .../test_relative_fields.py | 87 ------------------- 4 files changed, 5 insertions(+), 143 deletions(-) diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index e551ed1dbe..9716d65cd0 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -20,7 +20,6 @@ from django.utils.encoding import force_text from django.utils.functional import cached_property, curry from django.utils.lru_cache import lru_cache from django.utils.translation import ugettext_lazy as _ -from django.utils.version import get_docs_version from . import Field from .related_descriptors import ( @@ -789,7 +788,7 @@ class ForeignKey(ForeignObject): } description = _("Foreign Key (type determined by related field)") - def __init__(self, to, on_delete=None, related_name=None, related_query_name=None, + def __init__(self, to, on_delete, related_name=None, related_query_name=None, limit_choices_to=None, parent_link=False, to_field=None, db_constraint=True, **kwargs): try: @@ -808,29 +807,6 @@ class ForeignKey(ForeignObject): # be correct until contribute_to_class is called. Refs #12190. to_field = to_field or (to._meta.pk and to._meta.pk.name) - if on_delete is None: - warnings.warn( - "on_delete will be a required arg for %s in Django 2.0. Set " - "it to models.CASCADE on models and in existing migrations " - "if you want to maintain the current default behavior. " - "See https://docs.djangoproject.com/en/%s/ref/models/fields/" - "#django.db.models.ForeignKey.on_delete" % ( - self.__class__.__name__, - get_docs_version(), - ), - RemovedInDjango20Warning, 2) - on_delete = CASCADE - - elif not callable(on_delete): - warnings.warn( - "The signature for {0} will change in Django 2.0. " - "Pass to_field='{1}' as a kwarg instead of as an arg.".format( - self.__class__.__name__, - on_delete, - ), - RemovedInDjango20Warning, 2) - on_delete, to_field = to_field, on_delete - kwargs['rel'] = self.rel_class( self, to, to_field, related_name=related_name, @@ -1028,33 +1004,8 @@ class OneToOneField(ForeignKey): description = _("One-to-one relationship") - def __init__(self, to, on_delete=None, to_field=None, **kwargs): + def __init__(self, to, on_delete, to_field=None, **kwargs): kwargs['unique'] = True - - if on_delete is None: - warnings.warn( - "on_delete will be a required arg for %s in Django 2.0. Set " - "it to models.CASCADE on models and in existing migrations " - "if you want to maintain the current default behavior. " - "See https://docs.djangoproject.com/en/%s/ref/models/fields/" - "#django.db.models.ForeignKey.on_delete" % ( - self.__class__.__name__, - get_docs_version(), - ), - RemovedInDjango20Warning, 2) - on_delete = CASCADE - - elif not callable(on_delete): - warnings.warn( - "The signature for {0} will change in Django 2.0. " - "Pass to_field='{1}' as a kwarg instead of as an arg.".format( - self.__class__.__name__, - on_delete, - ), - RemovedInDjango20Warning, 2) - to_field = on_delete - on_delete = CASCADE # Avoid warning in superclass - super(OneToOneField, self).__init__(to, on_delete, to_field=to_field, **kwargs) def deconstruct(self): diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt index ba01f5f0bc..1d03bf99f2 100644 --- a/docs/ref/models/fields.txt +++ b/docs/ref/models/fields.txt @@ -1277,11 +1277,6 @@ relation works. null=True, ) - .. deprecated:: 1.9 - - :attr:`~ForeignKey.on_delete` will become a required argument in Django - 2.0. In older versions it defaults to ``CASCADE``. - The possible values for :attr:`~ForeignKey.on_delete` are found in :mod:`django.db.models`: diff --git a/docs/releases/2.0.txt b/docs/releases/2.0.txt index 6fd8c906ef..3958d27dd2 100644 --- a/docs/releases/2.0.txt +++ b/docs/releases/2.0.txt @@ -249,3 +249,6 @@ these features. relative ones when the path is identical is also removed. * ``Field.rel`` and ``Field.remote_field.to`` are removed. + +* The ``on_delete`` argument for ``ForeignKey`` and ``OneToOneField`` are now + required. diff --git a/tests/invalid_models_tests/test_relative_fields.py b/tests/invalid_models_tests/test_relative_fields.py index 7c20a0fb99..2165e6dfb5 100644 --- a/tests/invalid_models_tests/test_relative_fields.py +++ b/tests/invalid_models_tests/test_relative_fields.py @@ -1,17 +1,12 @@ # -*- encoding: utf-8 -*- from __future__ import unicode_literals -import warnings - from django.core.checks import Error, Warning as DjangoWarning from django.db import models from django.db.models.fields.related import ForeignObject -from django.test import ignore_warnings from django.test.testcases import SimpleTestCase, skipIfDBFeature from django.test.utils import isolate_apps, override_settings from django.utils import six -from django.utils.deprecation import RemovedInDjango20Warning -from django.utils.version import get_docs_version @isolate_apps('invalid_models_tests') @@ -29,88 +24,6 @@ class RelativeFieldTests(SimpleTestCase): errors = field.check() self.assertEqual(errors, []) - @ignore_warnings(category=RemovedInDjango20Warning) - def test_valid_foreign_key_without_on_delete(self): - class Target(models.Model): - model = models.IntegerField() - - class Model(models.Model): - field = models.ForeignKey(Target, related_name='+') - - def test_foreign_key_without_on_delete_warning(self): - with warnings.catch_warnings(record=True) as warns: - warnings.simplefilter('always') # prevent warnings from appearing as errors - - class Target(models.Model): - model = models.IntegerField() - - class Model(models.Model): - field = models.ForeignKey(Target, related_name='+') - - self.assertEqual(len(warns), 1) - self.assertEqual( - str(warns[0].message), - 'on_delete will be a required arg for ForeignKey in Django ' - '2.0. Set it to models.CASCADE on models and in existing ' - 'migrations if you want to maintain the current default ' - 'behavior. See https://docs.djangoproject.com/en/%s/ref/models/fields/' - '#django.db.models.ForeignKey.on_delete' % get_docs_version(), - ) - - def test_foreign_key_to_field_as_arg(self): - with warnings.catch_warnings(record=True) as warns: - warnings.simplefilter('always') # prevent warnings from appearing as errors - - class Target(models.Model): - model = models.IntegerField() - - class Model(models.Model): - field = models.ForeignKey(Target, 'id') - - self.assertEqual(len(warns), 1) - self.assertEqual( - str(warns[0].message), - "The signature for ForeignKey will change in Django 2.0. " - "Pass to_field='id' as a kwarg instead of as an arg." - ) - - def test_one_to_one_field_without_on_delete_warning(self): - with warnings.catch_warnings(record=True) as warns: - warnings.simplefilter('always') # prevent warnings from appearing as errors - - class Target(models.Model): - model = models.IntegerField() - - class Model(models.Model): - field = models.OneToOneField(Target, related_name='+') - - self.assertEqual(len(warns), 1) - self.assertEqual( - str(warns[0].message), - 'on_delete will be a required arg for OneToOneField in Django ' - '2.0. Set it to models.CASCADE on models and in existing ' - 'migrations if you want to maintain the current default ' - 'behavior. See https://docs.djangoproject.com/en/%s/ref/models/fields/' - '#django.db.models.ForeignKey.on_delete' % get_docs_version(), - ) - - def test_one_to_one_field_to_field_as_arg(self): - with warnings.catch_warnings(record=True) as warns: - warnings.simplefilter('always') # prevent warnings from appearing as errors - - class Target(models.Model): - model = models.IntegerField() - - class Model(models.Model): - field = models.OneToOneField(Target, 'id') - - self.assertEqual(len(warns), 1) - self.assertEqual( - str(warns[0].message), - "The signature for OneToOneField will change in Django 2.0. " - "Pass to_field='id' as a kwarg instead of as an arg." - ) - def test_foreign_key_to_missing_model(self): # Model names are resolved when a model is being created, so we cannot # test relative fields in isolation and we need to attach them to a