Saturnix
Saturnix

Reputation: 10564

Django, check if exists but on many items from an array of properties

arr = [
{id: 1, filename: "a"},
{id: 2, filename: "b"},
]

If I wanted to check if a Django table has 2 items with properties corresponding to the above, I could do:

for n in arr:
    e = MyTable.objects.filter(id=n["id"], filename=n["filename"]).exists()
    if not e: # raise error

But this requires to do one query for each item in the array.

How can I do this in a single query?

I was thinking to chain Qs like this:

Q(id=n['id'],filename=n['filename']) | Q(id=n['id'],filename=n['filename']) | ...for each item in array

But then how I could I check if each separate Q returns at least one entry?

I don't care about looping over arr as long as I don't do a query for each iteration.

Upvotes: 3

Views: 1320

Answers (2)

Gaurav Dhameeja
Gaurav Dhameeja

Reputation: 362

Make a list of all the ids and filenames, then use __in https://docs.djangoproject.com/en/2.2/ref/models/querysets/#in

ids = [item.get('id') for item in arr]
filenames = [item.get('filename') for item in arr]
qs = MyTable.objects.filter(id__in=ids, filename__in=filenames)
assert qs.count() == len(arr)

Upvotes: 2

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476567

Based on your comment, the items in arr all have a distinct id, so we can count the number of items that satisfy this condition. We know that this should be the same as the number of dictionaries in arr, since each Q(id=..., ...) can satisfy at most one record:

from functools import reduce
from operator import or_

MyTable.objects.filter(
    reduce(or_, [Q(id=n['id'],filename=n['filename']) for n in arr])
).count() == len(arr)

Upvotes: 4

Related Questions