#25987: Creating new object on adminsite with child model inlines and
unique_together raises IntegrityError
-------------------------------------+-------------------------------------
Reporter: MrYoda | Owner: nobody
Type: Bug | Status: new
Component: Forms | Version:
Severity: Normal | Resolution:
Keywords: admin, create | Triage Stage:
object, unique_together, | Unreviewed
IntegrityError, validate_unique |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by MrYoda):
I went deeper in formsets and wrote this for ChildModel:
{{{#!python
class ChildModelFormSet(BaseInlineFormSet):
def clean(self):
super().clean()
self.validate_unique_on_create()
def validate_unique_on_create(self):
""" Additional validation of unique
Copy-paste from BaseModelFormSet.validate_unique(), but removed
date checks and added "or 0" condition in row_data list comprehension to
prevent "None" values for not yet saved objects.
"""
# Collect unique_checks and date_checks to run from all the forms.
all_unique_checks = set()
forms_to_delete = self.deleted_forms
valid_forms = [form for form in self.forms if form.is_valid() and
form not in forms_to_delete]
for form in valid_forms:
exclude = form._get_validation_exclusions()
unique_checks, _ =
form.instance._get_unique_checks(exclude=exclude)
all_unique_checks =
all_unique_checks.union(set(unique_checks))
errors = []
# Do each of the unique checks (unique and unique_together)
for uclass, unique_check in all_unique_checks:
seen_data = set()
for form in valid_forms:
# get data for each field of each of unique_check
row_data = (form.cleaned_data[field]
for field in unique_check if field in
form.cleaned_data)
# Reduce Model instances to their primary key values
row_data = tuple(d._get_pk_val() or 0 if hasattr(d,
'_get_pk_val') else d
for d in row_data)
if row_data and None not in row_data:
# if we've already seen it then we have a uniqueness
failure
if row_data in seen_data:
# poke error messages into the right places and
mark
# the form as invalid
errors.append(self.get_unique_error_message(unique_check))
form._errors[NON_FIELD_ERRORS] =
self.error_class([self.get_form_error()])
# remove the data from the cleaned_data dict since
it was invalid
for field in unique_check:
if field in form.cleaned_data:
del form.cleaned_data[field]
# mark the data as seen
seen_data.add(row_data)
if errors:
raise ValidationError(errors)
}}}
It works fine and gracefully as I think. Workaround or not?
--
Ticket URL: <https://code.djangoproject.com/ticket/25987#comment:2>
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 post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/064.b16eeeebb6bdf498b646dd111880883d%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.