Як визначити два пари "унікальними" як пару


388

Чи є спосіб визначити пару полів як унікальних у Django?

У мене є таблиця томів (журналів), і я не хочу більше одного тома для одного журналу.

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)

Я намагався поставити в unique = Trueякості атрибута в поле journal_idі , volume_numberале він не працює.

Відповіді:


634

Для вас є просте рішення під назвою unique_together, яке робить саме те, що ви хочете.

Наприклад:

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

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

І у вашому випадку:

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',)

2
Я б сказав, що ви отримаєте "ValidationError" виняток. Подивіться на документи Django: Model.validate_unique
Jens

2
Як би ви впоралися з цим скажінням, якщо об'єм_кілька може бути нульовим? Mysql, здається, не застосовує унікальні в цьому випадку.
Грег

26
FYI він викидає django.db.utils.IntegrityError, якщо ви спробуєте додати дублікат.
araneae

8
@Greg - Відповідно до стандарту ANSI SQL: 2003 (а також попередніх), UNIQUEобмеження повинно забороняти дублювати нецінніNULL значення, але допускати декілька NULLзначень (див. Проект wiscorp.com/sql_2003_standard.zip , Framework, стор. 22). Якщо ви хочете, щоб ваше унікальне обмеження забороняло кілька нульових значень, ви, ймовірно, робите щось не так, наприклад, використовуючи NULLяк значуще значення. Пам'ятайте, що зведене поле говорить: "Ми не завжди маємо значення для цього поля, але коли ми це робимо, воно повинно бути унікальним".

2
А як щодо кількох unique_togetherобмежень? Наприклад - коли я хочу, щоб стовпці режимів були унікальними в області батьків? Ну, це властивість на насправді сам кортеж, см: docs.djangoproject.com/en/1.4/ref/models/options / ... Так що ваше обмеження повинно бути більш явним чином записати в вигляді: unique_together = (('journal_id', 'volume_number',),).
Томаш Гандор

76

Джанго 2.2+

Використання constraintsфункцій UniqueConstraintвіддається перевазі порівняно унікальним .

З документації Django для unique_together:

Використовуйте натомість UniqueConstraint з опцією обмежень.
UniqueConstraint надає більше функціональних можливостей, ніж унікальний.
У майбутньому унікальний_целе може бути застарілим.

Наприклад:

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')
        ]

У якій ситуації буде використовуватися параметр 'name' UniqueConstraint? Я припускаю, що він працює як параметр імені URL-шляху?
користувач7733611

1
@ user7733611 іменування обмеження може бути корисним у ряді ситуацій. Наприклад, якщо ви підключаєтесь до застарілої бази даних, або якщо ви просто хочете, щоб імена обмежень були легше читатими в базі даних. Одного разу я мігрував набір символів бази даних MySQL, і генеровані іменами обмеження Django насправді були занадто довгими для нашої конкретної цілі.
махі

Не на 100% впевнений, що це відбувається, UniqueConstraintале мені стає дивно, psycopg2.errors.DuplicateTable: relation "name_of_the_constraint" already existsколи я
переходжу
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.