Come definire due campi "unici" come coppia


388

C'è un modo per definire un paio di campi come unici in Django?

Ho una tabella di volumi (di riviste) e non voglio più di un numero di volume per lo stesso giornale.

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)

Ho provato a mettere unique = Truecome attributo nei campi journal_ide volume_numberma non funziona.

Risposte:


635

C'è una soluzione semplice per te chiamata unique_together che fa esattamente quello che vuoi.

Per esempio:

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

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

E nel tuo caso:

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
Direi che otterrai un'eccezione "ValidationError". Dai un'occhiata ai documenti di Django: Model.validate_unique
Jens,

2
Come gestiresti questo dire se volume_number potrebbe essere nullo? Mysql non sembrerà far valere unico in quel caso.
Greg,

26
Cordiali saluti genera un django.db.utils.IntegrityError se si tenta di aggiungere un duplicato.
Araneae,

8
@Greg - Secondo lo standard ANSI SQL: 2003 (e anche quelli precedenti), un UNIQUEvincolo dovrebbe non consentire duplicati di non NULLvalori, ma consentire NULLvalori multipli (consultare la bozza di wiscorp.com/sql_2003_standard.zip , Framework, p. 22). Se si desidera che il proprio vincolo univoco non consenta più valori null, probabilmente si sta facendo qualcosa di sbagliato, come l'utilizzo NULLcome valore significativo. Ricorda, il campo nullable dice "Non abbiamo sempre un valore per quel campo ma quando lo facciamo deve essere unico".

2
E i unique_togethervincoli multipli ? Ad esempio: quando desidero che le colonne della modalità siano univoche nell'ambito del genitore? Ebbene, questa proprietà è in realtà una tupla stessa, vedi: docs.djangoproject.com/en/1.4/ref/models/options/... Così il vostro vincolo dovrebbe essere più esplicito scritto come: unique_together = (('journal_id', 'volume_number',),).
Tomasz Gandor,

77

Django 2.2+

L'uso delle constraintsfunzionalità UniqueConstraintè preferito rispetto a unique_together .

Dalla documentazione di Django per unique_together:

Utilizzare invece UniqueConstraint con l'opzione di vincoli.
UniqueConstraint offre più funzionalità di unique_together.
unique_together potrebbe essere deprecato in futuro.

Per esempio:

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

In quale situazione verrebbe utilizzato il parametro "name" di UniqueConstraint? Presumo che funzioni come il parametro name di un percorso URL?
user7733611,

1
@ user7733611 la denominazione del vincolo può essere utile in diverse situazioni. Ad esempio, se ci si sta connettendo a un database legacy o se si desidera semplicemente che i nomi dei vincoli siano più leggibili nel database. Una volta ho migrato il set di caratteri di un database MySQL e i nomi dei vincoli generati da Django erano in realtà troppo lunghi per il nostro obiettivo specifico.
mihow

Non ne sono sicuro al 100%, UniqueConstraintma psycopg2.errors.DuplicateTable: relation "name_of_the_constraint" already exists
divento
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.