Search code examples
pythondjangodjango-rest-frameworkdjango-viewsdjango-filter

How to queryset filter with two lists?


I am very new to django, I have two list and I want to filter the values from table. I was using this query but this is giving me unions of two list i.e OR. I want something with AND i.e filter values this way retail_item_list = [100,120] and city_id_list = [1,2] the output should be on the basis of these combination (100,1) (120,2)

val = list(KVIItem.objects.filter(Q(retail_item_id__in=retail_item_list, cms_city_id__in=city_id_list)).values("retail_item_id","cms_city_id","active","id").order_by('-id'))

EDIT 1: Example

retail_item_list = [10005681, 10005681, 10013955, 10013955, 10067631]
city_id_list = [959, 956, 959, 956, 2074]

Using this query

qfilter = Q(
            *[
                Q(cms_city_id=city,retail_item_id=retail)
                for city,retail in zip(city_id_list,retail_item_list)
            ],
            _connector=Q.OR
        )
        val = list(KVIItem.objects.filter(qfilter).values("retail_item_id","cms_city_id","active","id").order_by('-id'))

I am getting the result of these combinations: (10005681,956), (10013955,959), (10013955,956), (10067631,2074)

But the goal is to get these combination result: (10005681,959), (10005681,956), (10013955,959), (10013955,956), (10067631,2074)

This one is missing from my result: (10005681,959) [first combination]

EDIT 2: qfilter print

"(OR: (AND: ('cms_city_id', 959), ('retail_item_id', 10005681)), (AND: ('cms_city_id', 956), ('retail_item_id', 10005681)), (AND: ('cms_city_id', 959), ('retail_item_id', 10013955)), (AND: ('cms_city_id', 956), ('retail_item_id', 10013955)), (AND: ('cms_city_id', 2074), ('retail_item_id', 10067631)))"

EDIT 3: this function will return higher id row.

def get_latest_kvi_item_among_same_items(val):
    dct = {}
    for v in val:
        if v['cms_city_id'] not in dct:
            dct[v['cms_city_id']] = v
        else:
            d = dct[v['cms_city_id']]
            if v['id'] > d['id']:
                dct['cms_city_id'] = v
    valus = dct.values()
    a = list(valus)
    return a

Solution

  • You can construct a Q object that will elementwise require that if retail_item is 100, then city_id should be 1; or if retail_item is 120 and city_id is 2.

    We can do that with:

    from django.db.models import Q
    
    qfilter = Q(
        *[
            Q(retail_item_id=retail, cms_city_id=city)
            for retail, city in zip(retail_item_list, city_id_list)
        ],
        _connector=Q.OR
    )
    
    KVIItem.objects.filter(qfilter)