0

Suppose I have the following Django models:

class myClass1(models.Model):
    myField1 = models.IntegerField()     


class myClass2(models.Model):
    myLocalClass1 = models.ManyToManyField(myClass1)     

Furthermore, suppose I have a list of unique myClass1s:

a = myClass1(myField=1)
b = myClass1(myField=2)
c = myClass1(myField=3)
myTargetList = [a, b, c]

Now, I would like to write a Django query using Q objects such that it returns all the myClass2s that have any member of myTargetList as myLocalClass1. Furthermore, I don't know the exact size of myTargetList in advance.

How should I do it? This obviously won't work:

myClass2.objects.filter(Q(myLocalClass1__in=myTargetList))
Tomasz Jakub Rup
  • 10,502
  • 7
  • 48
  • 49
Saqib Ali
  • 11,931
  • 41
  • 133
  • 272
  • 1
    `myClass2.objects.filter(myLocalClass1__in=myTargetList)` will work (assuming those have IDs and are saved to the DB). What is your question, if not this? Are you looking for myClass2 objects that have exactly the items in myTargetList? – Yuji 'Tomita' Tomita Jun 06 '13 at 17:13

2 Answers2

1

You nearly have it, you don't need Q objects, you can just use a combination of in and values_list:

l = myClass1.objects.filter(myField__in=[1, 2, 3]).values_list("id", flat=True)
myClass2.objects.filter(myLocalClass1__pk__in=l) 
Timmy O'Mahony
  • 53,000
  • 18
  • 155
  • 177
  • No, I don't believe this is correct. In this case your list l will be a list of ids of all the myClass1s in myTargetList. So filtering myClass2 on these ids doesn't make sense. How do we translate the list of myClass1 ids into the correct list of myClass2 ids? – Saqib Ali Jun 06 '13 at 16:35
  • You want to get all `myClass2` objects that feature at least 1 of the `myClass1` objects in the list right? – Timmy O'Mahony Jun 06 '13 at 16:39
  • Yes. But I don't believe thats what your solution does. Your solution gets a list of the IDs of the myClass1's I'm interested in. Then it looks for myClass2s that match those IDs. That's not right (unless I'm really missing something very major. But I don't think I am) – Saqib Ali Jun 06 '13 at 19:42
  • Ahh ok apologies its a typo it should be myLocalClass1__pk__in instead of just pk__in – Timmy O'Mahony Jun 06 '13 at 19:58
  • That's already been taken care of in the first query. The reason for searching with pks is that you don't have to join the tables (although the orm does this anyway internally I think) – Timmy O'Mahony Jun 06 '13 at 20:04
1

You can do this:

myclass1_qs = myClass1.objects.filter(myField__in=[1, 2, 3])
myclass2_qs = myClass2.objects.filter(myLocalClass1__in=myclass1_qs).distinct()

Or Here is a one liner,

myclass2_qs = myClass2.objects.filter(myLocalClass1__myField__in=[1, 2, 3]).distinct() 
karthikr
  • 97,368
  • 26
  • 197
  • 188
  • This is quite elegant.... and it works -- almost. The problem is that myclass2_qs now contains all the MyClass2s that meet the criteria. However, it contains duplicate MyClass2s for those MyClass2s that are linked to more than one myClass1s. How to make sure that myclass2_qs doesn't contain duplicates? Of course I could do this in python. But it would be most efficient if the database layer did this before passing the answer back to me. Right? – Saqib Ali Jun 06 '13 at 19:40
  • you need to use the `.distinct()` clause in the queryset. – karthikr Jun 06 '13 at 19:51