我的代码中有这个模型:
class Conversation(models.Model):
participants = models.ManyToManyField(User, related_name="message_participants")
我需要通过“参与者”多对多字段过滤这个“对话”模型对象。 意思是:我有3个用户对象,所以我想检索唯一的“对话”对象,在其“参与者”字段中有这3个用户。
我试过这样做:
def get_exist_conv_or_none(sender,recipients):
conv = Conversation.objects.filter(participants=sender)
for rec in recipients:
conv = conv.filter(participants=rec)
其中sender是User对象,“recipients”是User对象列表。 它不会引发错误,但它给了我错误的对话对象。 感谢。
编辑: 最近的一次尝试引导我:
def get_exist_conv_or_none(sender,recipients):
participants=recipients
participants.append(sender)
conv = Conversation.objects.filter(participants__in=participants)
return conv
基本上有同样的问题。它产生的对象在列表中有一个或多个“参与者”。但我正在寻找的是多对多对象的精确匹配。 意思是,一个具有确切“用户”的对象是多对多的关系。
编辑2:我的最后一次尝试。仍然,不会工作。
def get_exist_conv_or_none(sender,recipients):
recipients.append(sender)
recipients = list(set(recipients))
conv = Conversation.objects.annotate(count=Count('participants')).filter(participants=recipients[0])
for participant in recipients[1:]:
conv.filter(participants=participant)
conv.filter(count=len(recipients))
return conv
答案 0 :(得分:6)
好的,我找到了答案: 为了进行精确匹配,我必须对模型进行链式过滤,然后确保它具有所需的确切数量的参数,以便多对多字段中包含 all 所需的对象,不再需要。
我将使用注释检查对象编号:(https://docs.djangoproject.com/en/dev/topics/db/aggregation/)
最终得到了这段代码:
def get_exist_conv_or_none(recipients):
conv = Conversation.objects.annotate(count=Count('participants')).filter(participants=recipients[0])
for participant in recipients[1:]:
conv = conv.filter(participants=participant)
conv = conv.filter(count=len(recipients))
return conv
答案 1 :(得分:2)
对于使用数据库索引的快速搜索,我使用以下代码:
class YandexWordstatQueue(models.Model):
regions = models.ManyToManyField(YandexRegion)
regions_cached = models.CharField(max_length=10000, editable=False, db_index=True)
phrase = models.ForeignKey(SearchPhrase, db_index=True)
tstamp = models.DateTimeField(auto_now_add=True)
class YandexWordstatRecord(models.Model):
regions = models.ManyToManyField(YandexRegion)
regions_cached = models.CharField(max_length=10000, editable=False, db_index=True)
phrase = models.ForeignKey(SearchPhrase, db_index=True)
Shows = models.IntegerField()
date = models.DateField(auto_now_add=True)
@receiver(m2m_changed, sender=YandexWordstatRecord.regions.through)
@receiver(m2m_changed, sender=YandexWordstatQueue.regions.through)
def yandexwordstat_regions_changed(sender, **kwargs):
if kwargs.get('action') in ['post_add', 'post_remove']:
instance = kwargs.get('instance')
l = list(instance.regions.values_list('RegionID', flat=True))
l.sort()
instance.regions_cached = json.dumps(l)
instance.save()
这会增加保存时的开销,但现在我可以使用此代码段执行快速过滤:
region_ids = [1, 2, 3] # or list(some_queryset.values_list(...))
region_ids.sort()
regions_cahed = json.dumps(region_ids)
YandexWordstatQueue.objects.filter(regions_cached=regions_cached)