Django 外键的唯一组合

81 投票
7 回答
65578 浏览
提问于 2025-04-16 08:31

我遇到了一种情况,我想用 unique_together 的 Meta 选项来强制执行某个规则,这里是中间模型:

class UserProfileExtension(models.Model):
    extension = models.ForeignKey(Extension, unique=False)
    userprofile = models.ForeignKey(UserProfile, unique=False)
    user = models.ForeignKey(User, unique=False)  

    class Meta:
        unique_together = (("userprofile", "extension"),
                           ("user", "extension"),
                           # How can I enforce UserProfile's Client 
                           # and Extension to be unique? This obviously
                           # doesn't work, but is this idea possible without
                           # creating another FK in my intermediary model 
                           ("userprofile__client", "extension"))

这是 UserProfile:

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    client = models.ForeignKey(Client)

谢谢。

7 个回答

13

我的解决办法是使用Django的 get_or_create 方法。通过使用这个方法,如果数据库中已经有这条记录,就会进行一次无用的获取操作;如果没有这条记录,就会创建一条新的。

举个例子:

 
extension = Extension.objects.get(pk=someExtensionPK)
userProfile = UserProfile.objects.get(pk=someUserProfilePK)
UserProfileExtension.objects.get_or_create(extension=extension, userprofile=userProfile)
18

我来补充一下@Wolph的回答,分享我的看法。

其实你可以自己添加验证,只需要重写validate_unique这个方法,然后把这个验证加进去就行了。

下面是一个可以用的示例代码,可能会对某些人有帮助。

from django.core.exceptions import ValidationError


class MyModel(models.Model):

    fk = models.ForeignKey(AnotherModel, on_delete=models.CASCADE)

    my_field = models.CharField(...)  # whatever

    def validate_unique(self, *args, **kwargs):
        super().validate_unique(*args, **kwargs)
        if self.__class__.objects.\
                filter(fk=self.fk, my_field=self.my_field).\
                exists():
            raise ValidationError(
                message='MyModel with this (fk, my_field) already exists.',
                code='unique_together',
            )
91

你不能这样做。

unique_together 这个设置直接对应到 SQL 中的唯一索引。也就是说,你只能在同一个表的列上设置这个,而不能在多个表的组合上设置。

不过,你可以自己添加验证,只需要重写 validate_unique 方法,然后把这个验证加进去就可以了。

文档链接:http://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.validate_unique

撰写回答