#35676: ExclusionConstraint that includes a ForeignKey fails validation in
ModelForm
-----------------------------+-----------------------------------------
Reporter: diesieben07 | Type: Uncategorized
Status: new | Component: Uncategorized
Version: 5.1 | Severity: Normal
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-----------------------------+-----------------------------------------
I'm not sure if the summary above is good, but let me demonstrate:
{{{
class BlockedDaysConfig(models.Model):
name = models.CharField(max_length=255)
class BlockedDaysRange(models.Model):
config = models.ForeignKey(BlockedDaysConfig,
on_delete=models.CASCADE, related_name='days')
date_range = DateRangeField()
class Meta:
constraints = (
ExclusionConstraint(
name='%(app_label)s_%(class)s_no_overlapping_ranges_per_config',
expressions=(
('config_id', RangeOperators.EQUAL, ),
('date_range', RangeOperators.OVERLAPS, ),
)
),
)
}}}
`BlockedDaysRange` represents a range of blocked days. `BlockedDaysConfig`
represents a range of these blocked days. Example:
A BlockedDaysConfig with name "School Holidays in Germany" contains
several BlockedDaysConfig entries, one for "summer holidays", one for
"winter holidays", etc.
The exclusion constraint validates that the date ranges within one config
do not overlap.
Now I have configured a ModelAdmin for this:
{{{
class BlockedDaysRangeInline(admin.TabularInline):
model = BlockedDaysRange
@admin.register(BlockedDaysConfig)
class BlockedDaysConfigAdmin(admin.ModelAdmin):
inlines = (BlockedDaysRangeInline, )
}}}
The problem now happens when saving, because `BaseModelForm._post_clean`
will ''exclude'' the `InlineForeignKey` for `config` when calling
`full_clean` (see
https://github.com/django/django/blob/b99c608ea10cabc97a6b251cdb6e81ef2a83bdcf/django/forms/models.py#L477-L488).
Because `config` is in `exclude`, when `ExclusionConstraint` eventually
calls `_get_field_value_map`, the `config` is not included and thus a
nonsensical SQL query happens (`WHERE config_id=config_id and date_range
&& '[2024-01-01,2024-01-03)'::daterange`). This will now validate against
''any'' date ranges, not just ones with the same `config_id`.
As you can see from the comment in the code snippet linked above, this
problem is already recognized for unique constraints, which are handled
specially by `ModelForm`.
--
Ticket URL: <https://code.djangoproject.com/ticket/35676>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/010701914c624924-03d7e5a1-19f4-4888-a575-645070c37a5f-000000%40eu-central-1.amazonses.com.