在 Django 中强制使用唯一的字段组合

Posted

技术标签:

【中文标题】在 Django 中强制使用唯一的字段组合【英文标题】:Enforcing unique combinations of fields in Django 【发布时间】:2014-06-01 23:27:30 【问题描述】:

有一个模型可以链接多个项目,例如:

from django.db import models

class MyModel(models.Model):
    name = models.CharField(max_length=100)

    def __unicode__(self):
        return self.name

class MyModelItem(models.Model):
    TYPE_CHOICES = (
        ('A', 'A NAME'),
        ('B', 'B NAME'),
        ('C', 'C NAME')
    )
    name = models.CharField(max_length=100)
    model = models.ForeignKey(MyModel, related_name='items')
    item_type = models.CharField(max_length=1, choices=TYPE_CHOICES)

    def __unicode__(self):
        return self.name

要求是:对于MyModel的每条记录,不允许有多个MyModelItem的记录具有相同的item_type,这意味着如果我有:

from myproj.myapp.models import MyModel, MyModelItem

m1 = MyModel.objects.create(name='M1')

MyModelItem.objects.create(name='Item1', model=m1, item_type='A')

那么我无法将具有相同类型“A”的另一条记录添加到m1

我的一个解决方案是在MyModelItem 中这样做:

    ...
    def save(self, *args, **kwargs):
        if self.model.items.filter(item_type=self.item_type):
            raise IntegrityError("%s already have a item with type %s" % (self.model, self.item_type))
        super(MyModelItem, self).save(*args, **kwargs)

但这不会保护数据库级别的限制。可以直接使用 SQL 添加此类不允许的记录,它可能会破坏我的应用程序。有没有办法在 Django 中实现这个要求? unique_together 之类的东西?

【问题讨论】:

【参考方案1】:

你明白了,unique_together 就是这样做的方法。很简单:

class MyModelItem(models.Model): 
    ...
    name = models.CharField(max_length=100)
    model = models.ForeignKey(MyModel, related_name='items')
    item_type = models.CharField(max_length=1, choices=TYPE_CHOICES)

    class Meta:
        unique_together = ('model', 'item_type')

【讨论】:

我不记得为什么我认为“unique_together”不能满足我的要求,太愚蠢了。感谢您的回答和对我问题的更新,以纠正我糟糕的英语。 值得注意的是,首先需要迁移,然后才添加unique_together约束并再次运行迁移。

以上是关于在 Django 中强制使用唯一的字段组合的主要内容,如果未能解决你的问题,请参考以下文章

Django:列出一个字段组合其所有唯一值的所有内容

在 Postgresql 中,对两列的组合强制唯一

在 Postgresql 中,对两列的组合强制唯一

在一个字符字段中使用两个模型字段组合的 Django ModelForm

为啥不能在 Django ManyToMany 字段上强制执行唯一性?

Mongoose:如何将字段组合定义为唯一?