#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 , 3 months ago
Severity: | Normal → Release blocker |
---|---|
Triage Stage: | Unreviewed → Accepted |
comment:2 by , 3 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 , 3 months ago
Has patch: | set |
---|---|
Needs documentation: | set |
Needs tests: | set |
Patch needs improvement: | set |
comment:4 by , 3 months ago
Owner: | set to |
---|---|
Status: | new → assigned |
comment:5 by , 3 months ago
Version: | dev → 5.0 |
---|
comment:6 by , 3 months ago
Needs documentation: | unset |
---|---|
Needs tests: | unset |
Patch needs improvement: | unset |
follow-up: 8 comment:7 by , 3 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 , 3 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 , 3 months ago
Patch needs improvement: | unset |
---|
Turns out we did need it… unsetting pending any further reviews & follow-ups 😅
comment:10 by , 3 months ago
Triage Stage: | Accepted → Ready for checkin |
---|
Thank you for your report!
We should adjust
_get_field_value_map
to 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=True
andunique_together
validations thatvalidate_unique
provides are also affected e.g.I haven't tested the above but I don't see any special handling of
db_default
invalidate_unique
Marking as release blocker as
db_default
was introduced in 5.0.