5👍
Your models work correctly in that extent that the right unique index is created:
$ python manage.py sqlmigrate app 0001_initial
...
CREATE UNIQUE INDEX "app_base_slug_version_a455c5b7_uniq" ON "app_base" ("slug", "version");
...
(expected like the name of your application is “app”)
I must roughly agree with user3541631’s answer. It depends on the database in general, but all four db engines supported directly by Django are similar. They expect that “nulls are distinct in a UNIQUE column” (see NULL Handling in SQLite Versus Other Database Engines)
I verified your problem with and without null:
class Test(TestCase):
def test_without_null(self):
timestamp = datetime.datetime(2017, 8, 25, tzinfo=pytz.UTC)
book_1 = Book.objects.create(deleted=timestamp, first_form_number='a')
with self.assertRaises(django.db.utils.IntegrityError):
Book.objects.create(deleted=timestamp, first_form_number='a')
def test_with_null(self):
# this test fails !!! (and a duplicate is created)
book_1 = Book.objects.create(first_form_number='a')
with self.assertRaises(django.db.utils.IntegrityError):
Book.objects.create(first_form_number='a')
A solution is possible for PostgreSQL if you are willing to manually write a migration to create two special partial unique indexes:
CREATE UNIQUE INDEX book_2col_uni_idx ON app_book (first_form_number, deleted)
WHERE deleted IS NOT NULL;
CREATE UNIQUE INDEX book_1col_uni_idx ON app_book (first_form_number)
WHERE deleted IS NULL;
See:
- Answer for Create unique constraint with null columns
- Django docs Writing database migrations
- Django docs migrations.RunSQL(sql)
1👍
depending on your database, it is possible that NULL isn’t equal to any other NULL.
Therefore the rows you create are not the same, if one of the values is NULL, will be unique only by the non null field, in your case ‘first_form_number’.
Also take in consideration that is case sensitive so “char” and “Char” are not the same.
I had a similar situation and I did my own check by overriding the save method on the model.
You check if exist in the database, but also exclude the current instance, in case of updating, not to compare with itself..
if not deleted:
exists = model.objects.exclude(pk=instance.pk).filter(first_form_number__iexact=first_form_number).exists()
- [Django]-Why do we write [0] after get_or_create in model_name.object.get_or_create() in django
- [Django]-ImportError: No module named context_processors
-1👍
Make sure you actually extend the inherited Meta
class, rather than defining your own Meta
class (which is ignored by Django):
class Meta(BaseModel.Meta):
unique_together = (("first_form_number", "deleted"),)
- [Django]-JSONField serializes as json for POST, but string for GET
- [Django]-PyCharm: auto-insert Django template closing-tags ( {% endif %} {% endfor %} , etc. ) option?
- [Django]-Django model method vs custom manager
- [Django]-Loading Fixtures Django
- [Django]-Django throwing "invalid literal for int() with base 10: ''" when trying to save object attribute