Jak zdefiniować dwa pola „unikalne” jako para

388

Czy istnieje sposób na zdefiniowanie kilku pól jako unikalnych w Django?

Mam tabelę woluminów (dzienników) i nie chcę więcej niż jednego numeru woluminu dla tego samego dziennika.

class Volume(models.Model):
    id = models.AutoField(primary_key=True)
    journal_id = models.ForeignKey(Journals, db_column='jid', null=True, verbose_name = "Journal")
    volume_number = models.CharField('Volume Number', max_length=100)
    comments = models.TextField('Comments', max_length=4000, blank=True)

Starałem się umieścić unique = Truejako atrybut w polach journal_idi volume_numberale to nie działa.

Giovanni Di Milia
źródło

Odpowiedzi:

634

Istnieje dla Ciebie proste rozwiązanie o nazwie Unique_together, które robi dokładnie to, co chcesz.

Na przykład:

class MyModel(models.Model):
  field1 = models.CharField(max_length=50)
  field2 = models.CharField(max_length=50)

  class Meta:
    unique_together = ('field1', 'field2',)

A w twoim przypadku:

class Volume(models.Model):
  id = models.AutoField(primary_key=True)
  journal_id = models.ForeignKey(Journals, db_column='jid', null=True, verbose_name = "Journal")
  volume_number = models.CharField('Volume Number', max_length=100)
  comments = models.TextField('Comments', max_length=4000, blank=True)

  class Meta:
    unique_together = ('journal_id', 'volume_number',)
Jens
źródło
2
Powiedziałbym, że otrzymasz wyjątek „ValidationError”. Spójrz na dokumenty Django: Model.validate_unique
Jens
2
Jak byś sobie poradził z tym, gdyby liczba_objętości mogła być zerowa? W tym przypadku Mysql nie będzie egzekwował unikalności.
Greg
26
FYI zgłasza błąd django.db.utils.IntegrityError, jeśli spróbujesz dodać duplikat.
araneae
8
@Greg - Zgodnie ze standardem ANSI SQL: 2003 (i poprzednimi) UNIQUEograniczenie powinno uniemożliwiać powielanie innych NULLwartości, ale zezwalać na wiele NULLwartości (patrz szkic wiscorp.com/sql_2003_standard.zip , Framework, s. 22). Jeśli chcesz, aby twoje unikalne ograniczenie uniemożliwiało wiele wartości zerowych, prawdopodobnie robisz coś złego, na przykład używając NULLwartości znaczącej. Pamiętaj, że pole zerowalne mówi „Nie zawsze mamy wartość dla tego pola, ale kiedy to robimy, musi być unikalne”.
2
Co z wieloma unique_togetherograniczeniami? Na przykład - kiedy chcę, aby kolumny trybu były unikalne w zakresie elementu nadrzędnego? Cóż, ta właściwość jest w rzeczywistości sama krotka, patrz: docs.djangoproject.com/en/1.4/ref/models/options/... Więc ograniczeniem powinna być bardziej wyraźnie zapisać jako: unique_together = (('journal_id', 'volume_number',),).
Tomasz Gandor
76

Django 2.2+

Korzystanie z constraintsfunkcji UniqueConstraintjest lepsze niż unikalne .

Z dokumentacji Django dla unique_together:

Zamiast tego użyj UniqueConstraint z opcją ograniczeń.
UniqueConstraint zapewnia więcej funkcjonalności niż Unique_together.
Unique_together może być przestarzałe w przyszłości.

Na przykład:

class Volume(models.Model):
    id = models.AutoField(primary_key=True)
    journal_id = models.ForeignKey(Journals, db_column='jid', null=True, verbose_name="Journal")
    volume_number = models.CharField('Volume Number', max_length=100)
    comments = models.TextField('Comments', max_length=4000, blank=True)

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['journal_id', 'volume_number'], name='name of constraint')
        ]
daaawx
źródło
W jakiej sytuacji można zastosować parametr „name” ograniczenia UniqueConint? Zakładam, że działa jak parametr nazwy ścieżki URL?
user7733611
1
@ user7733611 nazwanie ograniczenia może być pomocne w wielu sytuacjach. Na przykład, jeśli łączysz się ze starszą bazą danych lub po prostu chcesz, aby nazwy ograniczeń były bardziej czytelne dla ludzi w bazie danych. Pewnego razu przeprowadziłem migrację zestawu znaków bazy danych MySQL, a wygenerowane przez Django nazwy ograniczeń były w rzeczywistości zbyt długie dla naszego konkretnego celu.
mihow
Nie jestem w 100% pewien, że pochodzi, UniqueConstraintale dziwnie się psycopg2.errors.DuplicateTable: relation "name_of_the_constraint" already existsprzestawiam na Postgres
zar3bski 17.10.19