Fixed #36722 -- Allowed selecting zero in MySQL auto fields using expressions.

This commit is contained in:
Clifford Gama 2025-11-10 13:28:07 +02:00
parent c4e07f94eb
commit e33dd72b6e
3 changed files with 18 additions and 7 deletions

View file

@ -2810,10 +2810,13 @@ class AutoFieldMixin:
pass pass
def get_db_prep_value(self, value, connection, prepared=False): def get_db_prep_value(self, value, connection, prepared=False):
if not prepared: return value if prepared else self.get_prep_value(value)
value = self.get_prep_value(value)
value = connection.ops.validate_autopk_value(value) def get_db_prep_save(self, value, connection):
return value if hasattr(value, "as_sql"):
return value
value = connection.ops.validate_autopk_value(value)
return self.get_db_prep_value(value, connection=connection, prepared=False)
def contribute_to_class(self, cls, name, **kwargs): def contribute_to_class(self, cls, name, **kwargs):
if cls._meta.auto_field: if cls._meta.auto_field:

View file

@ -19,6 +19,7 @@ from django.db import (
from django.db.backends.base.base import BaseDatabaseWrapper from django.db.backends.base.base import BaseDatabaseWrapper
from django.db.backends.signals import connection_created from django.db.backends.signals import connection_created
from django.db.backends.utils import CursorWrapper from django.db.backends.utils import CursorWrapper
from django.db.models import BigAutoField, Value
from django.db.models.sql.constants import CURSOR from django.db.models.sql.constants import CURSOR
from django.test import ( from django.test import (
TestCase, TestCase,
@ -966,7 +967,7 @@ class ThreadTests(TransactionTestCase):
connection.dec_thread_sharing() connection.dec_thread_sharing()
class MySQLPKZeroTests(TestCase): class MySQLAutoPKZeroTests(TestCase):
""" """
Zero as id for AutoField should raise exception in MySQL, because MySQL Zero as id for AutoField should raise exception in MySQL, because MySQL
does not allow zero for autoincrement primary key if the does not allow zero for autoincrement primary key if the
@ -975,8 +976,15 @@ class MySQLPKZeroTests(TestCase):
@skipIfDBFeature("allows_auto_pk_0") @skipIfDBFeature("allows_auto_pk_0")
def test_zero_as_autoval(self): def test_zero_as_autoval(self):
with self.assertRaises(ValueError): msg = "The database backend does not accept 0 as a value for AutoField."
with self.assertRaisesMessage(ValueError, msg):
Square.objects.create(id=0, root=0, square=1) Square.objects.create(id=0, root=0, square=1)
with self.assertRaisesMessage(ValueError, msg):
Square.objects.create(id=Value(0, BigAutoField()), root=0, square=1)
@skipIfDBFeature("allows_auto_pk_0")
def test_no_error_when_filtering_with_expression(self):
self.assertSequenceEqual(Square.objects.filter(id=Value(0, BigAutoField())), ())
class DBConstraintTestCase(TestCase): class DBConstraintTestCase(TestCase):

View file

@ -198,7 +198,7 @@ class IntegerFieldTests(TestCase):
(TypeError, {}), (TypeError, {}),
(TypeError, set()), (TypeError, set()),
(TypeError, object()), (TypeError, object()),
(TypeError, complex()), (TypeError, complex(0, 1)),
(ValueError, "non-numeric string"), (ValueError, "non-numeric string"),
(ValueError, b"non-numeric byte-string"), (ValueError, b"non-numeric byte-string"),
] ]