Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #17653 -- Changed MySQL backend to raise a ValueError if zero i…

…s 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
  • Loading branch information...
commit c4e62eff9074bedb5f2242b46625c35721502989 1 parent 612247b
Anssi Kääriäinen authored April 24, 2012
8  django/db/backends/__init__.py
@@ -770,6 +770,14 @@ def prep_for_like_query(self, x):
770 770
     # need not necessarily be implemented using "LIKE" in the backend.
771 771
     prep_for_iexact_query = prep_for_like_query
772 772
 
  773
+    def validate_autopk_value(self, value):
  774
+        """
  775
+        Certain backends do not accept some values for "serial" fields
  776
+        (for example zero in MySQL). This method will raise a ValueError
  777
+        if the value is invalid, otherwise returns validated value.
  778
+        """
  779
+        return value
  780
+
773 781
     def value_to_db_date(self, value):
774 782
         """
775 783
         Transform a date value to an object compatible with what is expected
7  django/db/backends/mysql/base.py
@@ -276,6 +276,13 @@ def sql_flush(self, style, tables, sequences):
276 276
         else:
277 277
             return []
278 278
 
  279
+    def validate_autopk_value(self, value):
  280
+        # MySQLism: zero in AUTO_INCREMENT field does not work. Refs #17653.
  281
+        if value == 0:
  282
+            raise ValueError('The database backend does not accept 0 as a '
  283
+                             'value for AutoField.')
  284
+        return value
  285
+
279 286
     def value_to_db_datetime(self, value):
280 287
         if value is None:
281 288
             return None
6  django/db/models/fields/__init__.py
@@ -531,6 +531,12 @@ def to_python(self, value):
531 531
     def validate(self, value, model_instance):
532 532
         pass
533 533
 
  534
+    def get_db_prep_value(self, value, connection, prepared=False):
  535
+        if not prepared:
  536
+            value = self.get_prep_value(value)
  537
+            value = connection.ops.validate_autopk_value(value)
  538
+        return value
  539
+
534 540
     def get_prep_value(self, value):
535 541
         if value is None:
536 542
             return None
15  tests/regressiontests/backends/tests.py
@@ -13,7 +13,8 @@
13 13
 from django.db.backends.signals import connection_created
14 14
 from django.db.backends.postgresql_psycopg2 import version as pg_version
15 15
 from django.db.utils import ConnectionHandler, DatabaseError, load_backend
16  
-from django.test import TestCase, skipUnlessDBFeature, TransactionTestCase
  16
+from django.test import (TestCase, skipUnlessDBFeature, skipIfDBFeature,
  17
+    TransactionTestCase)
17 18
 from django.test.utils import override_settings
18 19
 from django.utils import unittest
19 20
 
@@ -642,3 +643,15 @@ def test_old_style_backends_raise_useful_exception(self):
642 643
         self.assertRaisesRegexp(ImproperlyConfigured,
643 644
             "Try using django.db.backends.sqlite3 instead",
644 645
             load_backend, 'sqlite3')
  646
+
  647
+
  648
+class MySQLPKZeroTests(TestCase):
  649
+    """
  650
+    Zero as id for AutoField should raise exception in MySQL, because MySQL
  651
+    does not allow zero for automatic primary key.
  652
+    """
  653
+
  654
+    @skipIfDBFeature('allows_primary_key_0')
  655
+    def test_zero_as_autoval(self):
  656
+        with self.assertRaises(ValueError):
  657
+            models.Square.objects.create(id=0, root=0, square=1)
16  tests/regressiontests/bulk_create/tests.py
@@ -2,7 +2,7 @@
2 2
 
3 3
 from operator import attrgetter
4 4
 
5  
-from django.test import TestCase, skipUnlessDBFeature
  5
+from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
6 6
 
7 7
 from .models import Country, Restaurant, Pizzeria, State
8 8
 
@@ -56,4 +56,16 @@ def test_non_auto_increment_pk(self):
56 56
             ])
57 57
         self.assertQuerysetEqual(State.objects.order_by("two_letter_code"), [
58 58
             "CA", "IL", "ME", "NY",
59  
-        ], attrgetter("two_letter_code"))
  59
+        ], attrgetter("two_letter_code"))
  60
+
  61
+    @skipIfDBFeature('allows_primary_key_0')
  62
+    def test_zero_as_autoval(self):
  63
+        """
  64
+        Zero as id for AutoField should raise exception in MySQL, because MySQL
  65
+        does not allow zero for automatic primary key.
  66
+        """
  67
+
  68
+        valid_country = Country(name='Germany', iso_two_letter='DE')
  69
+        invalid_country = Country(id=0, name='Poland', iso_two_letter='PL')
  70
+        with self.assertRaises(ValueError):
  71
+            Country.objects.bulk_create([valid_country, invalid_country])

0 notes on commit c4e62ef

Please sign in to comment.
Something went wrong with that request. Please try again.