Django Unique Together(带外键)

chi*_*rox 58 python django-models

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

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"))
Run Code Online (Sandbox Code Playgroud)

这是UserProfile:

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    client = models.ForeignKey(Client)
Run Code Online (Sandbox Code Playgroud)

谢谢.

Wol*_*lph 69

你不能.

unique_together子句直接转换为SQL唯一索引.而且您只能在单个表的列上设置它们,而不能在几个表的组合中设置它们.

您可以自己添加验证,只需覆盖该validate_unique方法并将此验证添加到其中.

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


Jas*_*ski 11

我的解决方案是使用Django的get_or_create.通过使用get_or_create,如果数据库中已存在该行,则将发生无用的get,如果该行不存在,则将创建该行.

例:

 
extension = Extension.objects.get(pk=someExtensionPK)
userProfile = UserProfile.objects.get(pk=someUserProfilePK)
UserProfileExtension.objects.get_or_create(extension=extension, userprofile=userProfile)
Run Code Online (Sandbox Code Playgroud)


Man*_*anu 6

我的2美分,补充了@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(MyModel, self).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',
            )
Run Code Online (Sandbox Code Playgroud)


Har*_*hid 5

您需要调用Models.full_clean()方法来调用foreignKey的validate_unique。您可以重写 save() 来调用它

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


    def save(self, *args, **kwargs):
        self.full_clean()
        super().save(*args, **kwargs)

    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"))
Run Code Online (Sandbox Code Playgroud)