Code

Ticket #17653: ticket_17653.diff

File ticket_17653.diff, 3.0 KB (added by akaariai, 2 years ago)

Some initial work

Line 
1diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
2index ebe8875..5ee04cd 100644
3--- a/django/db/backends/__init__.py
4+++ b/django/db/backends/__init__.py
5@@ -640,6 +640,14 @@ class BaseDatabaseOperations(object):
6         """
7         return 'DEFAULT'
8 
9+    def validate_autopk_value(self, value):
10+        """
11+        Certain backends have limitations for what values can be used as
12+        autofield values. This method will return True if the value is usable,
13+        else False.
14+        """
15+        return True
16+
17     def process_clob(self, value):
18         """
19         Returns the value of a CLOB column, for backends that return a locator
20diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py
21index 830808b..32a18c0 100644
22--- a/django/db/backends/mysql/base.py
23+++ b/django/db/backends/mysql/base.py
24@@ -226,6 +226,11 @@ class DatabaseOperations(BaseDatabaseOperations):
25         # 2**64 - 1, as recommended by the MySQL documentation
26         return 18446744073709551615L
27 
28+    def validate_autopk_value(self, value):
29+        if value == 0:
30+            return False
31+        return True
32+
33     def quote_name(self, name):
34         if name.startswith("`") and name.endswith("`"):
35             return name # Quoting once is enough.
36diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
37index 42b727d..6cc7ed1 100644
38--- a/django/db/models/fields/__init__.py
39+++ b/django/db/models/fields/__init__.py
40@@ -535,6 +535,13 @@ class AutoField(Field):
41             return None
42         return int(value)
43 
44+    def get_db_prep_save(self, value, connection):
45+        prepared = self.get_prep_value(value)
46+        if not connection.ops.validate_autopk_value(prepared):
47+            raise ValueError('The database backend does not accept %s as a '
48+                             'value for field %s' % (prepared, self.name))
49+        return prepared
50+
51     def contribute_to_class(self, cls, name):
52         assert not cls._meta.has_auto_field, \
53                "A model can't have more than one AutoField."
54diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py
55index cfb662e..fdd5b83 100644
56--- a/tests/regressiontests/backends/tests.py
57+++ b/tests/regressiontests/backends/tests.py
58@@ -618,3 +618,18 @@ class BackendLoadingTests(TestCase):
59         self.assertRaisesRegexp(ImproperlyConfigured,
60             "Try using django.db.backends.sqlite3 instead",
61             load_backend, 'sqlite3')
62+
63+class MySQLAutoValueTests(TestCase):
64+    """
65+    Test a bug in MySQL where zero as a value to autofield gets ignored.
66+
67+    As this test is safe to run on other backends, no need to skip them.
68+    """
69+    def test_zero_as_autoval(self):
70+        models.Square.objects.create(id=0, root=0, square=1)
71+        models.Square.objects.all().delete()
72+        s = models.Square(id=0, root=0, square=1)
73+        models.Square.objects.bulk_create([s])
74+        models.Square.objects.all().delete()
75+        s = models.Square(id=0, root=0, square=1)
76+        s.save()