#35638 closed Bug (fixed)
validate_constraints() fails on models with fields using db_default
| Reported by: | David Sanders | Owned by: | David Sanders |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 5.0 |
| Severity: | Release blocker | Keywords: | db_default |
| Cc: | Triage Stage: | Ready for checkin | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Follow up to #35223
Related forum thread: https://forum.djangoproject.com/t/proposal-to-have-db-default-considered-in-model-forms/33358/3
Given the model
class Foo(models.Model):
bar = models.CharField(db_default="bar")
class Meta:
constraints = [
models.CheckConstraint(check=models.Q(bar="bar"), name="is_bar"),
]
validating constraints should ideally not fail but currently does:
>>> foo = Foo()
>>> foo.validate_constraints()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/path/to/django/django/db/models/base.py", line 1598, in validate_constraints
raise ValidationError(errors)
django.core.exceptions.ValidationError: {'__all__': ['Constraint “is_bar” is violated.']}
I couldn't find an easy workaround for this.
If I apply this small patch to Q.check(), then validate_constraints() uses the default expression and runs a suitable check query. Perhaps can take this as a starting point and add something similar to Django?
index 1bf396723e..5380cc17d0 100644
--- a/django/db/models/query_utils.py
+++ b/django/db/models/query_utils.py
@@ -120,12 +120,16 @@ class Q(tree.Node):
"""
# Avoid circular imports.
from django.db.models import BooleanField, Value
+ from django.db.models.expressions import DatabaseDefault
from django.db.models.functions import Coalesce
from django.db.models.sql import Query
from django.db.models.sql.constants import SINGLE
query = Query(None)
for name, value in against.items():
+ # not ideal, value is wrapped in a Value by Model._get_field_value_map()
+ if isinstance(getattr(value, "value"), DatabaseDefault):
+ value = value.field.db_default
if not hasattr(value, "resolve_expression"):
value = Value(value)
query.add_annotation(value, name, select=False)
Change History (16)
comment:1 by , 15 months ago
| Severity: | Normal → Release blocker |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
comment:2 by , 15 months ago
We should adjust _get_field_value_map to take into account db_default (and possibly rename to _get_field_expr_map) so all constraints are adjusted appropriately.
👍 Yup was also thinking this so good to see some confirmation there
I suspect that other constraints as well as the unique=True and unique_together validations that validate_unique provides are also affected e.g.
Ah nice, I didn't think of this. Whoever picks this test up will need to write a test for that too ☝️
I was thinking of starting a PR tomorrow if I have time, but if someone else want to pick it up before then - you're welcome to do so.
comment:3 by , 15 months ago
| Has patch: | set |
|---|---|
| Needs documentation: | set |
| Needs tests: | set |
| Patch needs improvement: | set |
comment:4 by , 15 months ago
| Owner: | set to |
|---|---|
| Status: | new → assigned |
comment:5 by , 15 months ago
| Version: | dev → 5.0 |
|---|
comment:6 by , 15 months ago
| Needs documentation: | unset |
|---|---|
| Needs tests: | unset |
| Patch needs improvement: | unset |
follow-up: 8 comment:7 by , 15 months ago
Patch needs improvement: unset
Just need to verify whether we still want to keep the changes to _get_field_value_map() … may no longer necessary with Simon's more recent suggestion
comment:8 by , 15 months ago
| Patch needs improvement: | set |
|---|
Replying to David Sanders:
Just need to verify whether we still want to keep the changes to
_get_field_value_map()… may no longer necessary with Simon's more recent suggestion
Ah sorry! I'll let you unset when you're ready
comment:9 by , 15 months ago
| Patch needs improvement: | unset |
|---|
Turns out we did need it… unsetting pending any further reviews & follow-ups 😅
comment:10 by , 15 months ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
Thank you for your report!
We should adjust
_get_field_value_mapto take into accountdb_default(and possibly rename to_get_field_expr_map) so all constraints are adjusted appropriately. I suspect that other constraints as well as theunique=Trueandunique_togethervalidations thatvalidate_uniqueprovides are also affected e.g.I haven't tested the above but I don't see any special handling of
db_defaultinvalidate_uniqueMarking as release blocker as
db_defaultwas introduced in 5.0.