Django unique together constraint failure?
Django unique together constraint failure?
--
Become part of the top 3% of the developers by applying to Toptal
https://topt.al/25cXVn
--
Music by Eric Matyas
https://www.soundimage.org
Track title: Melt
--
Chapters
00:00 Question
01:44 Accepted answer (Score 26)
02:15 Answer 2 (Score 1)
02:52 Answer 3 (Score 0)
04:08 Answer 4 (Score 0)
04:40 Thank you
--
Full question
https://stackoverflow.com/questions/1751...
Answer 3 links:
[Create unique constraint with null columns]: https://stackoverflow.com/questions/8289...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#python #django #postgresql
#avk47
ACCEPTED ANSWER
Score 26
In Postgresql NULL isn't equal to any other NULL. Therefore the rows you create are not the same (from Postgres' perspective).
Update
You have a few ways to deal with it:
- Forbid the
Nullvalue for foreign key and use some default value - Override the
savemethod of your model to check that no such row exists - Change SQL standard :)
ANSWER 2
Score 1
Add a clean method to your model, so you can edit an existing row.
def clean(self):
queryset = MO.objects.exclude(id=self.id).filter(slug=self.slug)
if self.foreign_key is None:
if queryset.exists():
raise ValidationError("A row already exists with this slug and no key")
else:
if queryset.filter(foreign_key=self.foreign_key).exists():
raise ValidationError("This row already exists")
Beware, clean (or full_clean) isn't called by the default save method.
NB: if you put this code in the save method, update forms (like in the admin) won't work: you will have a traceback error due to the ValidationError exception.
ANSWER 3
Score 0
Just manually create secondary index on slug field, but only for NULL values in foreign_key_id:
CREATE INDEX table_name_unique_null_foreign_key
ON table_name (slug) WHERE foreign_key_id is NULL
Please note, that Django does not support this, so without custom form/model validation you will get pure IntegrityError / 500.
Possible duplicate of Create unique constraint with null columns
ANSWER 4
Score 0
As hobbyte mentioned, "In Postgresql NULL isn't equal to any other NULL. Therefore the rows you create are not the same (from Postgres' perspective)."
Another possible way to address this challenge is to add custom validation at the view level in the form_valid method.
In views.py:
def form_valid(self, form):
--OTHER VALIDATION AND FIELD VALUE ASSIGNMENT LOGIC--
if ModelForm.objects.filter(slug=slug,foreign_key=foreign_key:
form.add_error('field',
forms.ValidationError( _("Validation error message that shows up in your form. "),
code='duplicate_row', ))
return self.form_invalid(form)
This approach is helpful if you are using class based views, especially if you are automatically assigning values to fields that you want to hide from the user.
Pros:
- You don't have to create dummy default values in the database
- You can still use update forms (see Toff's answer)
Cons: - This doesn't protect against duplicate rows created directly at the database level. - If you use Django's admin backend to create new MyModel objects, you'll need to add this same validation logic to your admin form.