简体   繁体   English

如何在多对多字段(完全匹配)中通过其对象过滤django模型?

[英]How to filter django model by its objects in many-to-many field (exact match)?

I have this model in my code: 我的代码中有这个模型:

class Conversation(models.Model):
    participants = models.ManyToManyField(User, related_name="message_participants")

and I need to filter this "Conversation" model objects by the "participants" many-to-many field. 我需要通过“参与者”多对多字段过滤这个“对话”模型对象。 meaning: I have for example 3 User objects, so I want to retrieve the only "Conversation" objects that has this 3 Users in it's "participants" field. 意思是:我有3个用户对象,所以我想检索唯一的“对话”对象,其中有3个用户在其“参与者”字段中。

I tried doing this: 我试过这样做:

def get_exist_conv_or_none(sender,recipients):
    conv = Conversation.objects.filter(participants=sender)
    for rec in recipients:
        conv = conv.filter(participants=rec)

where sender is a User object and "recipients" is a list of User objects. 其中sender是User对象,“recipients”是User对象列表。 it won't raise error but it gives me the wrong Object of Conversation. 它不会引发错误,但它给了我错误的对话对象。 Thanks. 谢谢。

edit: A more recent try lead me to this: 编辑:最近的一次尝试引导我:

def get_exist_conv_or_none(sender,recipients):
    participants=recipients
    participants.append(sender)
    conv = Conversation.objects.filter(participants__in=participants)
    return conv

which basically have the same problem. 这基本上有同样的问题。 It yields Objects which has one or more of the "participants" on the list. 它产生的对象在列表中有一个或多个“参与者”。 but what Im looking for is exact match of the many-to-many object. 但我正在寻找的是多对多对象的精确匹配。 Meaning, an Object with the exact "Users" on it's many-to-many relation. 意思是,一个具有确切“用户”的对象是多对多关系。

edit 2: My last attempt. 编辑2:我的最后一次尝试。 still, won't work. 仍然,不会工作。

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

Ok so I found the answer: In order to make an exact match I have to chain-filter the model and then make sure it has the exact number of arguments it needs to have, so that the many-to-many field will have in it all the objects needed and no more. 好的,我找到了答案:为了完全匹配,我必须对模型进行链式过滤,然后确保它具有所需的确切数量的参数,以便多对多字段将具有它需要的所有物品,而不是更多。

I will check for the objects number using annotation: ( https://docs.djangoproject.com/en/dev/topics/db/aggregation/ ) 我将使用注释检查对象编号:( https://docs.djangoproject.com/en/dev/topics/db/aggregation/

ended up with this code: 结束了这段代码:

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

For fast search using database index, I use this code: 对于使用数据库索引的快速搜索,我使用以下代码:

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()

This adds overhead when saving, but now I can perform fast filter with this snippet: 这会增加保存时的开销,但现在我可以使用此代码段执行快速过滤:

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM