【发布时间】:2019-03-28 05:58:32
【问题描述】:
在我的数据库中,我的用户对象上有两个多对多字段(消息和关注),它们都包含与另一个对象主题相关的多对多字段。
class User():
messages = ManyToManyField('Message', related_name='users', blank=True, null=True)
following = ForeignKey('Following', related_name='users', blank=True, null=True)
class Message():
date = DateField(blank=True, null=True)
content = TextField(blank=True, null=True)
topics = ManyToManyField('Topic', related_name='messages', blank=True, null=True)
class Following():
name = CharField(max_length=255, blank=True, null=True)
description = CharField(max_length=255, blank=True, null=True)
topics = ManyToManyField('Topic', related_name='following', blank=True, null=True)
class Topic():
name = CharField(max_length=255, blank=True, null=True)
source = CharField(max_length=255, blank=True, null=True)
我想过滤所有附加了“消息”的“用户”,这些“消息”不包含附加到用户“关注”对象的所有主题。
现在我正在使用循环来完成此操作:
users = set()
for user in User.objects.filter(messages__isnull=False, following__isnull=False).iterator():
if not set(user.following.values_list('topics', flat=True))
).issubset(set(user.messages.values_list('topics', flat=True)):
users.add(user.pk)
有没有办法用一个查询来完成同样的事情?
---- 编辑----
我拥有的是这样的:
User.objects.filter(following__isnull=False
).annotate(following_count=Count('following__topics', distinct=True)
).filter(following__topics__exact=F('message__topics')
).annotate(missing_topics=ExpressionWrapper(
F('following_count') - Count('message__topics', distinct=True),
IntegerField())
).filter(missing_topics__gt=0)
如果有更好的方法可以做到这一点,或者有理由我绝对不应该这样做,它们是什么?
---- 编辑----
This question帮助我理解和使用Håken Lid's answer
这是我的新模型和我的新查询:
class User():
messages = ManyToManyField('Message', related_name='users', blank=True, null=True)
following = ManyToManyField('Topic', through='Following', related_name='users', blank=True, null=True)
class Message():
date = DateField(blank=True, null=True)
content = TextField(blank=True, null=True)
topics = ManyToManyField('Topic', related_name='messages', blank=True, null=True)
class Following():
name = CharField(max_length=255, blank=True, null=True)
description = CharField(max_length=255, blank=True, null=True)
user = ForeignKey('User', related_name='following', blank=True, null=True)
topic = ForeignKey('Topic', related_name='following', blank=True, null=True)
class Topic():
name = CharField(max_length=255, blank=True, null=True)
source = CharField(max_length=255, blank=True, null=True)
User.objects.filter(~Q(messages__topics__in=F('following'))
).values('id').annotate(missing_topics=Count('following__topics', distinct=True))
【问题讨论】:
-
可以分享一下相关模型吗?
-
我添加了相关模型。
-
我不确定如何在单个查询中执行此操作。但是,如果您的用户比主题多(例如 stackoverflow),您可以尝试循环遍历每个主题而不是每个用户以提高性能。
标签: django django-queryset python-3.5