Cara mendefinisikan dua bidang "unik" sebagai pasangan

388

Apakah ada cara untuk mendefinisikan beberapa bidang sebagai unik di Django?

Saya memiliki daftar volume (jurnal) dan saya tidak ingin lebih dari satu nomor volume untuk jurnal yang sama.

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)

Saya mencoba menempatkan unique = Truesebagai atribut di bidang journal_iddan volume_numbertetapi tidak berhasil.

Giovanni Di Milia
sumber

Jawaban:

635

Ada solusi sederhana untuk Anda yang disebut unique_together yang melakukan persis apa yang Anda inginkan.

Sebagai contoh:

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

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

Dan dalam kasus Anda:

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
sumber
2
Saya akan mengatakan Anda akan mendapatkan pengecualian "ValidationError". Lihatlah dokumen Django: Model.validate_unique
Jens
2
Bagaimana Anda menangani ini mengatakan jika volume_number bisa menjadi nol? Mysql tampaknya tidak akan menerapkan keunikan dalam kasus itu.
Greg
26
FYI itu melempar django.db.utils.IntegrityError jika Anda mencoba menambahkan duplikat.
araneae
8
@Greg - Menurut standar ANSI SQL: 2003 (dan yang sebelumnya juga), UNIQUEkendala harus melarang duplikasi NULLnilai-nilai, tetapi memungkinkan beberapa NULLnilai (lihat konsep wiscorp.com/sql_2003_standard.zip , Framework, hal. 22). Jika Anda ingin batasan unik Anda melarang beberapa nilai null, Anda mungkin melakukan sesuatu yang salah, seperti menggunakan NULLsebagai nilai yang bermakna. Ingat, bidang nullable mengatakan, "Kami tidak selalu memiliki nilai untuk bidang itu, tetapi ketika kami melakukannya harus unik."
2
Bagaimana dengan banyak unique_togetherkendala? Misalnya - ketika saya ingin memiliki kolom mode menjadi unik dalam lingkup induknya? Nah, properti ini sebenarnya adalah sebuah tuple itu sendiri, lihat: docs.djangoproject.com/en/1.4/ref/models/options/... Jadi kendala Anda harus lebih eksplisit ditulis sebagai: unique_together = (('journal_id', 'volume_number',),).
Tomasz Gandor
77

Django 2.2+

Menggunakan constraintsfitur - fitur UniqueConstraintlebih disukai daripada unique_together .

Dari dokumentasi Django untuk unique_together:

Gunakan UniqueConstraint dengan opsi kendala sebagai gantinya.
UniqueConstraint menyediakan lebih banyak fungsionalitas daripada unique_together.
unique_together dapat ditinggalkan di masa depan.

Sebagai contoh:

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
sumber
Dalam situasi apa parameter 'nama' dari UniqueConstraint akan digunakan? Saya menganggap itu berfungsi seperti parameter nama jalur URL?
user7733611
1
@ user7733611 memberi nama kendala dapat membantu dalam sejumlah situasi. Misalnya jika Anda terhubung ke database lama, atau jika Anda hanya ingin nama kendala lebih mudah dibaca oleh manusia dalam database. Suatu kali saya memigrasikan rangkaian karakter dari database MySQL dan nama kendala yang dihasilkan Django sebenarnya terlalu panjang untuk target khusus kami.
mihow
Tidak 100% yakin itu berasal dari UniqueConstrainttetapi saya menjadi aneh psycopg2.errors.DuplicateTable: relation "name_of_the_constraint" already existsketika saya beralih ke Postgres
zar3bski