Как определить два поля «уникальные» как пару

389

Есть ли способ определить пару полей как уникальных в 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но он не работает.

Джованни ди Милия
источник

Ответы:

636

Для вас есть простое решение с названием 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',)
Jens
источник
2
Я бы сказал, что вы получите исключение «ValidationError». Посмотрите документы Django: Model.validate_unique
Jens
2
Как бы вы справились с этим, если бы volume_number мог быть нулевым? Mysql не будет обеспечивать уникальность в этом случае.
Грег
26
К вашему сведению, он выдает ошибку 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',),).
Томаш Гандор
78

Джанго 2.2+

Использование constraintsфункций UniqueConstraintпредпочтительнее, чем unique_together .

Из документации Django для unique_together:

Вместо этого используйте UniqueConstraint с опцией ограничений.
UniqueConstraint предоставляет больше функциональности, чем unique_together.
unique_together может устареть в будущем.

Например:

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
источник
В какой ситуации будет использоваться параметр name для UniqueConstraint? Я предполагаю, что это работает как параметр имени пути URL?
user7733611
1
@ user7733611 имя ограничения может быть полезным в ряде ситуаций. Например, если вы подключаетесь к устаревшей базе данных или просто хотите, чтобы имена ограничений были более удобочитаемыми в базе данных. Однажды я перенес набор символов базы данных MySQL, и сгенерированные имена ограничений Django были слишком длинными для нашей конкретной цели.
Mihow
Не на 100% уверен, что это исходит, UniqueConstraintно я psycopg2.errors.DuplicateTable: relation "name_of_the_constraint" already exists
становлюсь