Commit f39b0421 authored by Diego Guimarães's avatar Diego Guimarães Committed by Tim Graham
Browse files

Fixed #23338 -- Added warning when unique=True on ForeigKey

Thanks Jonathan Lindén for the initial patch, and Tim Graham
and Gabe Jackson for the suggestions.
parent abf87333
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -153,6 +153,7 @@ class ChangepasswordManagementCommandTestCase(TestCase):


@skipIfCustomUser
@override_settings(SILENCED_SYSTEM_CHECKS=['fields.W342'])  # ForeignKey(unique=True)
class CreatesuperuserManagementCommandTestCase(TestCase):

    def test_basic_usage(self):
+15 −0
Original line number Diff line number Diff line
@@ -1710,6 +1710,7 @@ class ForeignKey(ForeignObject):
    def check(self, **kwargs):
        errors = super(ForeignKey, self).check(**kwargs)
        errors.extend(self._check_on_delete())
        errors.extend(self._check_unique())
        return errors

    def _check_on_delete(self):
@@ -1735,6 +1736,16 @@ class ForeignKey(ForeignObject):
        else:
            return []

    def _check_unique(self, **kwargs):
        return [
            checks.Warning(
                'Setting unique=True on a ForeignKey has the same effect as using a OneToOneField.',
                hint='ForeignKey(unique=True) is usually better served by a OneToOneField.',
                obj=self,
                id='fields.W342',
            )
        ] if self.unique else []

    def deconstruct(self):
        name, path, args, kwargs = super(ForeignKey, self).deconstruct()
        del kwargs['to_fields']
@@ -1891,6 +1902,10 @@ class OneToOneField(ForeignKey):
        else:
            setattr(instance, self.attname, data)

    def _check_unique(self, **kwargs):
        # override ForeignKey since check isn't applicable here
        return []


def create_many_to_many_intermediary_model(field, klass):
    from django.db import models
+2 −0
Original line number Diff line number Diff line
@@ -154,6 +154,8 @@ Related Fields
* **fields.E339**: ``<model>.<field name>`` is not a foreign key to ``<model>``.
* **fields.W340**: ``null`` has no effect on ``ManyToManyField``.
* **fields.W341**: ``ManyToManyField`` does not support ``validators``.
* **fields.W342**: Setting ``unique=True`` on a ``ForeignKey`` has the same
  effect as using a ``OneToOneField``.

Signals
~~~~~~~
+5 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ from django.contrib.contenttypes.admin import GenericStackedInline
from django.core import checks
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase
from django.test.utils import override_settings

from .models import Song, Book, Album, TwoAlbumFKAndAnE, City, State, Influence

@@ -34,6 +35,10 @@ class ValidFormFieldsets(admin.ModelAdmin):
    )


@override_settings(
    SILENCED_SYSTEM_CHECKS=['fields.W342'],  # ForeignKey(unique=True)
    INSTALLED_APPS=['django.contrib.auth', 'django.contrib.contenttypes', 'admin_checks']
)
class SystemChecksTestCase(TestCase):

    def test_checks_are_performed(self):
+6 −4
Original line number Diff line number Diff line
@@ -8,7 +8,6 @@ from django.apps import apps
from django.conf import settings
from django.core import checks
from django.core.checks import Error, Warning
from django.core.checks.model_checks import check_all_models
from django.core.checks.registry import CheckRegistry
from django.core.checks.compatibility.django_1_7_0 import check_1_7_compatibility
from django.core.management.base import CommandError
@@ -303,7 +302,10 @@ class CheckFrameworkReservedNamesTests(TestCase):
            del self.current_models[model]
        apps.clear_cache()

    @override_settings(SILENCED_SYSTEM_CHECKS=['models.E020'])
    @override_settings(
        SILENCED_SYSTEM_CHECKS=['models.E20', 'fields.W342'],  # ForeignKey(unique=True)
        INSTALLED_APPS=['django.contrib.auth', 'django.contrib.contenttypes', 'check_framework']
    )
    def test_model_check_method_not_shadowed(self):
        class ModelWithAttributeCalledCheck(models.Model):
            check = 42
@@ -318,6 +320,7 @@ class CheckFrameworkReservedNamesTests(TestCase):
            check = models.ForeignKey(ModelWithRelatedManagerCalledCheck)
            article = models.ForeignKey(ModelWithRelatedManagerCalledCheck, related_name='check')

        errors = checks.run_checks()
        expected = [
            Error(
                "The 'ModelWithAttributeCalledCheck.check()' class method is "
@@ -341,5 +344,4 @@ class CheckFrameworkReservedNamesTests(TestCase):
                id='models.E020'
            ),
        ]

        self.assertEqual(check_all_models(), expected)
        self.assertEqual(errors, expected)
Loading