Cómo definir dos campos "únicos" como pareja

388

¿Hay alguna manera de definir un par de campos como únicos en Django?

Tengo una tabla de volúmenes (de revistas) y no quiero más de un número de volumen para la misma revista.

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)

Traté de poner unique = Truecomo atributo en los campos journal_idy volume_numberno funciona.

Giovanni Di Milia
fuente

Respuestas:

635

Hay una solución simple para usted llamada unique_together que hace exactamente lo que desea.

Por ejemplo:

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

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

Y en tu 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',)
Jens
fuente
2
Yo diría que obtendrá una excepción "ValidationError". Echa un vistazo a los documentos de Django: Model.validate_unique
Jens
2
¿Cómo manejarías este dicho si volume_number podría ser nulo? Mysql no parece imponer un único en ese caso.
Greg
26
Para su información, arroja un django.db.utils.IntegrityError si intenta agregar un duplicado.
araneae
8
@Greg: según el estándar ANSI SQL: 2003 (y también los anteriores), una UNIQUErestricción no debe permitir NULLvalores no duplicados , sino permitir NULLvalores múltiples (consulte el borrador wiscorp.com/sql_2003_standard.zip , Framework, p. 22). Si desea que su restricción única no permita múltiples valores nulos, probablemente esté haciendo algo mal, como usarlo NULLcomo un valor significativo. Recuerde, el campo anulable dice "No siempre tenemos un valor para ese campo, pero cuando lo hagamos debe ser único".
2
¿Qué pasa con las unique_togetherrestricciones múltiples ? Por ejemplo, ¿cuándo quiero que las columnas de modo sean únicas en el ámbito del padre? Pues bien, esta propiedad es en realidad una tupla en sí, ver: docs.djangoproject.com/en/1.4/ref/models/options/... Así que su limitación debe ser escrito de manera más explícita como: unique_together = (('journal_id', 'volume_number',),).
Tomasz Gandor
77

Django 2.2+

Se prefiere usar las constraintscaracterísticas UniqueConstraintsobre unique_together .

De la documentación de Django para unique_together:

Utilice UniqueConstraint con la opción de restricciones en su lugar.
UniqueConstraint proporciona más funcionalidades que unique_together.
unique_together puede quedar en desuso en el futuro.

Por ejemplo:

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
fuente
¿En qué situación se usaría el parámetro 'nombre' de UniqueConstraint? ¿Supongo que funciona como el parámetro de nombre de una ruta URL?
user7733611
1
@ user7733611 nombrar la restricción puede ser útil en varias situaciones. Por ejemplo, si se está conectando a una base de datos heredada, o si solo desea que los nombres de las restricciones sean más legibles para los humanos en la base de datos. Una vez migré el conjunto de caracteres de una base de datos MySQL y los nombres de restricciones generados por Django eran en realidad demasiado largos para nuestro objetivo particular.
mihow
No estoy 100% seguro de que provenga, UniqueConstraintpero me pongo raro psycopg2.errors.DuplicateTable: relation "name_of_the_constraint" already existscuando me cambio a Postgres
zar3bski