Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using prefetch_related to get only a particular entry of a relation

Assume the following models

Class A(): pass
Class B():
    i = integer()
    aa = foreignkey('A', related_name = 'fka')

For simplicity assume the below entries,

A() - a1 -> pk = 1
B() - b1 -> i = 1, aa = a1
B() - b2 -> i = 2, aa = a1
B() - b3 -> i = 3, aa = a1
B() - b4 -> i = 4, aa = a1
B() - b5 -> i = 5, aa = a1

I know,

foo = A.objects.get(pk = 1).prefetch_related('fka')

will give me the entries b1, b2, b3, b4 and b5.

But what I want to know is, is it possible to alter this query in anyway to get only a particular entry of B() associated with A(). Suppose I want to prefetch only entry of 'B', with 'i' as 2 (get b2, and skip b1, b3, b4 and b5).

If it is not possible to do it using the prefetch then, what is the best way to do it ?

Note: get(pk = 1) is used to keep the simplicity for explanation, but at that place usually there will be filter(**conditions).

like image 817
NEB Avatar asked Oct 27 '25 10:10

NEB


1 Answers

Is it necessary to do the query on the A objects rather than the B objects? If you reverse what you do the additional lookup on, you could use select_related():

foo = B.objects.select_related('aa').get(i=2)

This has the advantage of reducing your number of database hits. Because prefetch_related() always does its own database lookup, your proposed scenario of using prefetch_related() isn't any more efficient, as written, than simply doing:

a = A.objects.get(pk=1)
b = a.fka.get(i=2)

That's not to say it wouldn't be more efficient in scenarios with more complex filtering, but select_related() uses a SQL join and therefore only hits the database once. That said, if you absolutely must lookup the A objects first, the best answer would be: upgrade to Django 1.7. The new Prefetch command in Django 1.7 allows for more complex operations on prefetch_related(), including filtering, by allowing you to specify custom querysets:

qs = B.objects.filter(i=2)
foo = A.objects.get(pk = 1).prefetch_related(Prefetch('fka',qs))
like image 124
MBrizzle Avatar answered Oct 30 '25 07:10

MBrizzle



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!