Python Django Unique Together(带外键)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4440010/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 15:44:28  来源:igfitidea点击:

Django Unique Together (with foreign keys)

pythondjango-models

提问by chiurox

I have a situation where I want to use the Meta options of unique_togetherto enforce a certain rule, here's the intermediary model:

我有一种情况,我想使用 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"))

and here's UserProfile:

这是用户配置文件:

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

Thanks.

谢谢。

采纳答案by Wolph

You can't.

你不能。

The unique_togetherclause is directly translated to the SQLunique index. And you can only set those on columns of a single table, not a combination of several tables.

unique_together子句直接转换为SQL唯一索引。并且您只能在单个表的列上设置这些,而不能在多个表的组合上进行设置。

You can add validation for it yourself though, simply overwrite the validate_uniquemethod and add this validation to it.

不过,您可以自己为它添加验证,只需覆盖该validate_unique方法并将此验证添加到它。

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

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

回答by Jason Pudzianowski

My solution was to use Django's get_or_create. By using get_or_create, a useless get will occur if the row already exists in the database, and the row will be created if it does not exist.

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

Example:

例子:

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

回答by Manu

My 2 cents, complementingthe accepted response from @Wolph

我的 2 美分,补充了@Wolph 接受的回复

You can add validation for it yourself though, simply overwrite the validate_unique method and add this validation to it.

您可以自己为它添加验证,只需覆盖 validate_unique 方法并将此验证添加到它。

This is a working example code someone could find usefull.

这是某人可能会发现有用的工作示例代码。

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',
            )

回答by Harun-Ur-Rashid

You need to call Models.full_clean()method to call validate_unique for foreignKey. You can override save() to call this

您需要调用Models.full_clean()方法为外键调用 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"))

回答by HeisAif

from django.core.exceptions import ValidationError

.....

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

    def validate_unique(self, *args, **kwargs):
        super(UserProfileExtension, self).validate_unique(*args, **kwargs)
        query = UserProfileExtension.objects.filter(extension=self.extension)
        if query.filter(userprofile__client=self.userprofile.client).exists():
            raise ValidationError({'extension':['Extension already exits for userprofile__client',]})

The first query is to filter all records in UserProfileExtension model which has the same extension we are putting in the current record.

第一个查询是过滤 UserProfileExtension 模型中的所有记录,这些记录与我们在当前记录中放置的扩展名相同。

Then we filter the query returned to find if it already contains userprofile__client which we are passing in the current record.

然后我们过滤返回的查询以查找它是否已经包含我们在当前记录中传递的 userprofile__client 。