From 816b8d9518c41f034dcbacfd1f1826f2366975e5 Mon Sep 17 00:00:00 2001 From: Hasan Ramezani Date: Thu, 3 May 2018 11:38:29 +0430 Subject: [PATCH] Fixed #29358 -- Added a system check to prohibit models with more than one primary_key field. --- django/db/models/base.py | 14 ++++++++++++++ docs/ref/checks.txt | 1 + tests/invalid_models_tests/test_models.py | 13 +++++++++++++ 3 files changed, 28 insertions(+) diff --git a/django/db/models/base.py b/django/db/models/base.py index 9af6a8f92d..3573838b99 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -1189,6 +1189,7 @@ class Model(metaclass=ModelBase): *cls._check_field_name_clashes(), *cls._check_model_name_db_lookup_clashes(), *cls._check_property_name_related_field_accessor_clashes(), + *cls._check_single_primary_key(), ) errors.extend(clash_errors) # If there are field name clashes, hide consequent column name @@ -1436,6 +1437,19 @@ class Model(metaclass=ModelBase): ) return errors + @classmethod + def _check_single_primary_key(cls): + errors = [] + if sum(1 for f in cls._meta.local_fields if f.primary_key) > 1: + errors.append( + checks.Error( + "Model can not contain more than one 'primary_key' field.", + obj=cls, + id='models.E026', + ) + ) + return errors + @classmethod def _check_index_together(cls): """Check the value of "index_together" option.""" diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt index 1b9fa18328..9690b5a99b 100644 --- a/docs/ref/checks.txt +++ b/docs/ref/checks.txt @@ -295,6 +295,7 @@ Models as it collides with the query lookup syntax. * **models.E025**: The property ```` clashes with a related field accessor. +* **models.E026**: Model can not contain more than one ``primary_key`` field. Security -------- diff --git a/tests/invalid_models_tests/test_models.py b/tests/invalid_models_tests/test_models.py index cfd1a7c465..2066d4ebae 100644 --- a/tests/invalid_models_tests/test_models.py +++ b/tests/invalid_models_tests/test_models.py @@ -717,6 +717,19 @@ class OtherModelTests(SimpleTestCase): ) ]) + def test_single_primary_key(self): + class Model(models.Model): + foo = models.IntegerField(primary_key=True) + bar = models.IntegerField(primary_key=True) + + self.assertEqual(Model.check(), [ + Error( + "Model can not contain more than one 'primary_key' field.", + obj=Model, + id='models.E026', + ) + ]) + @override_settings(TEST_SWAPPED_MODEL_BAD_VALUE='not-a-model') def test_swappable_missing_app_name(self): class Model(models.Model):