【问题标题】:How to define two fields "unique" as couple如何将两个“唯一”字段定义为一对
【发布时间】:2011-01-13 04:22:38
【问题描述】:

有没有办法在 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_idvolume_number 字段中,但它不起作用。

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    有一个名为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',)
    

    【讨论】:

    • 我会说你会得到一个“ValidationError”异常。查看 Django 文档:Model.validate_unique
    • 如果volume_number 可以为空,你会如何处理这个说法?在这种情况下,Mysql 似乎不会强制执行唯一性。
    • 仅供参考,如果您尝试添加重复项,它会引发 django.db.utils.IntegrityError。
    • @Greg - 根据 ANSI 标准 SQL:2003(以及之前的标准),UNIQUE 约束应该不允许重复的非NULL 值,但允许多个 NULL 值(见草案wiscorp.com/sql_2003_standard.zip,框架,第 22 页)。如果您希望您的唯一约束不允许多个空值,那么您可能做错了,例如使用 NULL 作为有意义的值。请记住,可空字段表示“我们并不总是为该字段提供值,但当我们这样做时,它必须是唯一的。”。
    • 多个unique_together 约束怎么样?例如 - 当我想让模式列在父级范围内是唯一的?好吧,这个属性实际上是一个元组本身,见:docs.djangoproject.com/en/1.4/ref/models/options/… 所以你的约束应该更明确地写成:unique_together = (('journal_id', 'volume_number',),)
    【解决方案2】:

    Django 2.2+

    使用constraints 功能UniqueConstraint 优于unique_together

    来自unique_together 的 Django 文档:

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

    【讨论】:

    • UniqueConstraint的'name'参数在什么情况下使用?我认为它的工作原理类似于 URL 路径的名称参数?
    • @user7733611 命名约束在许多情况下都会有所帮助。例如,如果您要连接到旧数据库,或者您只是希望约束名称在数据库中更具可读性。有一次我迁移了 MySQL 数据库的字符集,Django 生成的约束名称实际上对于我们的特定目标来说太长了。
    • 不是 100% 确定它来自 UniqueConstraint,但当我切换到 Postgres 时我会觉得很奇怪 psycopg2.errors.DuplicateTable: relation "name_of_the_constraint" already exists
    • 请注意,CharField 等文本字段可以区分大小写或不区分大小写,具体取决于您的数据库配置!
    【解决方案3】:

    是的,您可以使用 Django 类 Meta 将多个字段定义为唯一字段:

    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 = ('volume_number', 'journal_id') 
    

    注意:
    为了使事情顺利进行,您不应将属性 unique=True 添加到您在 unique_together 属性中定义的任何字段中,否则它将无法作为唯一的一起使用。

    【讨论】:

      【解决方案4】:

      在 Django 4.0 中,

      UniqueConstraint() 的新 *expressions 位置参数启用 在表达式和数据库上创建功能唯一约束 职能。例如:

      from django.db import models
      from django.db.models import UniqueConstraint
      from django.db.models.functions import Lower
      
      
      class MyModel(models.Model):
          first_name = models.CharField(max_length=255)
          last_name = models.CharField(max_length=255)
      
          class Meta:
              constraints = [
                  UniqueConstraint(
                      Lower('first_name'),
                      Lower('last_name').desc(),
                      name='first_last_name_unique',
                  ),
              ]
      

      【讨论】:

        猜你喜欢
        • 2013-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-10
        • 1970-01-01
        相关资源
        最近更新 更多