布尔注释导致重复?

Posted

技术标签:

【中文标题】布尔注释导致重复?【英文标题】:Boolean annotation resulting in duplicates? 【发布时间】:2018-05-06 16:16:27 【问题描述】:

我正在尝试基于外键表实现一个基本的“收藏夹”系统。

假设我有以下简单模型:

class Item(models.Model)
  id = models.IntegerField()

class User(models.Model)
  id = models.IntegerField()

class UserFavourites(models.Model)
  user = models.ForeignKey(User, related_name='user_for_fav_rel')
  item = models.ForeignKey(Item, related_name='item_for_fav_rel')

现在我为项目生成以下查询集,以查看它们是否已被用户标记为收藏:

queryset = Item.objects.all()

USER_ID = request.user.id

queryset = queryset.annotate(
    favourite=Case(
        When(
            item_for_fav_rel__user__id=USER_ID,
            then=Value('True')
        ),
        default=Value('False'),
        output_field=BooleanField()
    )
)

所有这些都很好,但是在响应中,如果该项目确实被收藏了,我会在查询集中收到该特定项目的副本。知道如何避免这种情况吗?

结果 SQL 查询(编辑到我认为的最小示例......)

SELECT 
    "core_item"."id", 
    CASE 
        WHEN "core_userfavourites"."user_id" = 1 THEN True 
        ELSE False 
    END AS "favourite" 
FROM "core_item" 
LEFT OUTER JOIN "core_userfavourites" 
    ON ("core_item"."id" = "core_userfavourites"."item_id")

【问题讨论】:

它生成的 SQL 查询是什么? 查看问题编辑... 你使用all()然后annotate() 有什么特别的原因吗? @sharette 这是一个使用 django rest 框架的更大程序的一小部分。我正试图快速浏览它。 【参考方案1】:

问题是 core_item 和 core_userfavorites 的每个组合都有一行。如果没有原始 SQL,似乎没有办法完全按照您的要求进行操作,但幸运的是 Django 最近(1.11)添加了编写您可以在此处使用的 SubQuery 子句的能力

from django.db.models.expressions import OuterRef, Subquery

queryset = Item.objects.all()

USER_ID = request.user.id
user_favorites = UserFavourites.objects.filter(
    user_id=USER_ID, 
    item_id=OuterRef('id')
)[:1].values('user_id')

queryset = queryset.annotate(user_favorite=Subquery(user_favorites))

如果用户收藏了它,这将在user_favorite 字段中为您提供user_id,如果没有收藏,则为None

基本上,您正在编写一个子查询以从相关表中选择任意值。

【讨论】:

谢谢维奈!今晚晚些时候我会试试这个。问题:为什么要对子查询进行切片?这是否适用于布尔结果? 如果子查询返回多行,查询将失败。在这种情况下可能没有必要。您可能可以通过将子查询包装在原始表达式中的情况中来将其转换为布尔结果。我不确定这是否值得,尽管考虑到 None 将评估为 False 并且 user_id 的其他值将评估为 True。不过我承认它有点丑。如果 exists() 可以返回一个查询集或另一个可链接的对象,而不是触发执行并立即返回一个值,那就太好了。 再次感谢!这很好用。作为 Django Rest Framework 的一部分,我确实设法在“item”的序列化程序中将它包装成 True/False。

以上是关于布尔注释导致重复?的主要内容,如果未能解决你的问题,请参考以下文章

使用数据注释强制模型的布尔值为真

如何使用数据注释为模型属性 WebApi .NET Core 添加布尔验证

如何使用 Django ORM 将注释字符串转换为布尔值

continue与break 布尔值 整体注释:ctrl+?

布尔谓词导致零行数

Python:将字符串列表转换为布尔值,其中布尔值以字符串形式存在[重复]