S
S
sakuradaj2014-10-25 18:43:52
Django
sakuradaj, 2014-10-25 18:43:52

How to AND filter based on M2M relationship in Django?

There is an application with the following models:

class Code(models.Model):
    zip = models.CharField(unique=True)
    # ...

class Item(models.Model):
    code = models.ManyToManyField(Code)
    # ...

Let's say there are zip codes that need to be used for filtering: 1,2,3,4
You need to get Item 's that must have at least 4 links to Code , which have Code.zip values ​​1,2,3,4
This should work like this way:
for item in Item.objects.filter(...):
    zips = []
    for code in item.code.all():
        zips.append(code.zip)

    print zips
    # Здесь zips должны содержать 1,2,3,4

I would also like to know how to filter by exact match, i.e. find an Item that has 4 links to Code and whose Code.zip matches 1,2,3,4
(Perhaps it's worth adding another field to Item that will contain a sorted list of id from related Code objects)
I want to use this QuerySet in Django admin.
Tried: But here it turns out OR selection. I also tried with the Q object, but it turns out some kind of left request:
Item.objects.filter(code__zip__in=[1,2,3,4])


qs.filter(reduce(lambda x, y: x & y, [m.models.Q(code__zip=z) for z in [1,2,3,4]]))

How to implement it?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Anatoly Scherbakov, 2014-10-25
@sakuradaj

Не уверен в правильности, но может быть, попробовать вот так?
По идее, это даст эффект операции AND.
Если не сработает, существует ещё одно решение. Если не против, разобьём его составление на шаги, мне самому так проще писать.
1. Делаем запрос на промежуточной таблице отношения ManyToMany, которая связывает Item и Code, выбирая те пары Item - Code, для которых item__zip входит в нужное множество.
2. В результирующем запросе значения item_id будут повторяться. Нам нужно найти те значения, для которых число строк равняется четырём.

from django.db.models import Count
qs = qs.values('item_id').annotate(count=Count('id')).order_by().filter(count=4)

Надеюсь, что больших ошибок не допустил.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question