diff options
| author | Anssi Kääriäinen <akaariai@gmail.com> | 2012-04-24 18:03:14 +0000 |
|---|---|---|
| committer | Anssi Kääriäinen <akaariai@gmail.com> | 2012-04-24 18:03:14 +0000 |
| commit | c4e62eff9074bedb5f2242b46625c35721502989 (patch) | |
| tree | 83c2255db9b33f825d208e0d38e43fa65481b0d4 | |
| parent | 612247b3a0acbdec17b9c52410b2349533ff2d95 (diff) | |
Fixed #17653 -- Changed MySQL backend to raise a ValueError if zero is used as an AutoField value.
Thanks to Sylvain Lebon for the report, krzysiumed for the patch and charettes and claudep for reviews.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17933 bcc190cf-cafb-0310-a4f2-bffc1f526a37
| -rw-r--r-- | django/db/backends/__init__.py | 8 | ||||
| -rw-r--r-- | django/db/backends/mysql/base.py | 7 | ||||
| -rw-r--r-- | django/db/models/fields/__init__.py | 6 | ||||
| -rw-r--r-- | tests/regressiontests/backends/tests.py | 15 | ||||
| -rw-r--r-- | tests/regressiontests/bulk_create/tests.py | 16 |
5 files changed, 49 insertions, 3 deletions
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index 6f1f4b9618..0d664d452a 100644 --- a/django/db/backends/__init__.py +++ b/django/db/backends/__init__.py @@ -770,6 +770,14 @@ class BaseDatabaseOperations(object): # need not necessarily be implemented using "LIKE" in the backend. prep_for_iexact_query = prep_for_like_query + def validate_autopk_value(self, value): + """ + Certain backends do not accept some values for "serial" fields + (for example zero in MySQL). This method will raise a ValueError + if the value is invalid, otherwise returns validated value. + """ + return value + def value_to_db_date(self, value): """ Transform a date value to an object compatible with what is expected diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index bacd998fa5..6397a0972c 100644 --- a/django/db/backends/mysql/base.py +++ b/django/db/backends/mysql/base.py @@ -276,6 +276,13 @@ class DatabaseOperations(BaseDatabaseOperations): else: return [] + def validate_autopk_value(self, value): + # MySQLism: zero in AUTO_INCREMENT field does not work. Refs #17653. + if value == 0: + raise ValueError('The database backend does not accept 0 as a ' + 'value for AutoField.') + return value + def value_to_db_datetime(self, value): if value is None: return None diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index e240d39cc4..dc4495390a 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -531,6 +531,12 @@ class AutoField(Field): def validate(self, value, model_instance): pass + def get_db_prep_value(self, value, connection, prepared=False): + if not prepared: + value = self.get_prep_value(value) + value = connection.ops.validate_autopk_value(value) + return value + def get_prep_value(self, value): if value is None: return None diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py index 9b28787c15..3e675cc1ea 100644 --- a/tests/regressiontests/backends/tests.py +++ b/tests/regressiontests/backends/tests.py @@ -13,7 +13,8 @@ from django.db import (backend, connection, connections, DEFAULT_DB_ALIAS, from django.db.backends.signals import connection_created from django.db.backends.postgresql_psycopg2 import version as pg_version from django.db.utils import ConnectionHandler, DatabaseError, load_backend -from django.test import TestCase, skipUnlessDBFeature, TransactionTestCase +from django.test import (TestCase, skipUnlessDBFeature, skipIfDBFeature, + TransactionTestCase) from django.test.utils import override_settings from django.utils import unittest @@ -642,3 +643,15 @@ class BackendLoadingTests(TestCase): self.assertRaisesRegexp(ImproperlyConfigured, "Try using django.db.backends.sqlite3 instead", load_backend, 'sqlite3') + + +class MySQLPKZeroTests(TestCase): + """ + Zero as id for AutoField should raise exception in MySQL, because MySQL + does not allow zero for automatic primary key. + """ + + @skipIfDBFeature('allows_primary_key_0') + def test_zero_as_autoval(self): + with self.assertRaises(ValueError): + models.Square.objects.create(id=0, root=0, square=1) diff --git a/tests/regressiontests/bulk_create/tests.py b/tests/regressiontests/bulk_create/tests.py index 284ea9fdd9..0b55f637a4 100644 --- a/tests/regressiontests/bulk_create/tests.py +++ b/tests/regressiontests/bulk_create/tests.py @@ -2,7 +2,7 @@ from __future__ import absolute_import from operator import attrgetter -from django.test import TestCase, skipUnlessDBFeature +from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature from .models import Country, Restaurant, Pizzeria, State @@ -56,4 +56,16 @@ class BulkCreateTests(TestCase): ]) self.assertQuerysetEqual(State.objects.order_by("two_letter_code"), [ "CA", "IL", "ME", "NY", - ], attrgetter("two_letter_code"))
\ No newline at end of file + ], attrgetter("two_letter_code")) + + @skipIfDBFeature('allows_primary_key_0') + def test_zero_as_autoval(self): + """ + Zero as id for AutoField should raise exception in MySQL, because MySQL + does not allow zero for automatic primary key. + """ + + valid_country = Country(name='Germany', iso_two_letter='DE') + invalid_country = Country(id=0, name='Poland', iso_two_letter='PL') + with self.assertRaises(ValueError): + Country.objects.bulk_create([valid_country, invalid_country]) |
