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

10๐Ÿ‘

โœ…

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

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
๐Ÿ‘คSnirD

3๐Ÿ‘

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)
๐Ÿ‘คxy2

Leave a comment