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

Posted

技术标签:

【中文标题】为啥不能在 Django ManyToMany 字段上强制执行唯一性?【英文标题】:Why can't uniqueness be enforced on Django ManyToMany field?为什么不能在 Django ManyToMany 字段上强制执行唯一性? 【发布时间】:2015-11-18 21:37:49 【问题描述】:

我正在为我的网站创建一个简单的二元评级系统,它是一个学习资料网站,其摘要可以评级为 +1 或 -1。

我在 Summary 模型和 User 模型之间定义了 ManyToMany 字段,如下所示:

users_rated_positive = models.ManyToManyField(
    User, blank=True, related_name='summaries_rated_positive')
users_rated_negative = models.ManyToManyField(
    User, blank=True, related_name='summaries_rated_negative')

但是很明显,给定用户不能多次评价给定摘要。

我尝试设置 unique=True 但 Django 似乎不允许我这样做。

是否有更优化的方式来存储更符合我意图的评分?

【问题讨论】:

您是否检查过是否可以有效地添加重复关系?这个答案似乎暗示不允许重复关系:***.com/questions/4870935/… 所以我不需要在我的视图中实际检查这个? 我自己从未尝试过,所以不能确定,但​​这就是我链接的答案中描述的内容。您可以尝试重现要检查的答案中的测试用例。 【参考方案1】:

考虑使用多对多through table。

class Summary(models.Model):
    user_ratings = models.ManyToManyField(
        'User', blank=True, through='UserRating',
    )


class UserRating(models.Model):
    user = models.ForeignKey('User')
    summary = models.ForeignKey('Summary')
    is_positive = models.BooleanField()

    class Meta:
        unique_together = ('user', 'summary')

然后,您可以使用类似的方式查询积极评价摘要的用户

summary.user_ratings.filter(is_positive=True)
summary.user_ratings.filter(is_positive=False)

unique_together 属性确保用户不能两次查看同一个摘要。

您甚至可以使用自定义查询集保留类似的语法。以下是对它可能是什么样子的猜测:

class SummaryQuerySet(models.QuerySet):

    def users_rated_negative(self):
        return self.user_ratings.filter(is_positive=False)

    def users_rated_positive(self):
        return self.user_ratings.filter(is_positive=True)


class Summary(models.Model):
    user_ratings = models.ManyToManyField(
        'User', blank=True, through='UserRating',
    )

    objects = SummaryQuerySet.as_manager()

现在使用的语法是summary.users_rated_positive

如果您也需要,User 的类似自定义查询集将为您提供 summaries_rated_positive 属性。

【讨论】:

以上是关于为啥不能在 Django ManyToMany 字段上强制执行唯一性?的主要内容,如果未能解决你的问题,请参考以下文章

如何在模板上显示 Django ManyToMany?需要简单的代码

Django ManyToMany 关系详情详情

python django的ManyToMany简述

django - manytomany 上的查询过滤器为空

Django / Python - 在对象创建中使用ManyToMany字段

Django:模型设计,ManyToMany 属性字段?