Say I have these models:
models.py:
class Item(models.Model):
ref_id = models.PositiveIntegerField()
name = models.CharacterField(max_length=32)
class ItemDue(models.Model):
item = models.ForeignKey(Item)
due_date = models.DateField(null=True, blank=True)
lots of other fields below
.
.
.
I want to query the ItemDue
objects but want to also include the Item
with the query.
If I get a set of ItemDue
s I can loop like this:
for item_due in ItemDue.objects.filter(some_criteria):
print item_due.item.ref_id
However, when I did some performance tests, this is going back to the database to get the referenced Item
object, so I have to run another query for each ItemDue
to get the Item.ref_id
. This makes a difference in a huge query, so I want to get the Item.ref_id
along with the queryset to get the ItemDue
s. I can do .values('id', 'item__ref_id')
to get a dictionary of the ItemDue
with the id
and item__ref_id
. So, I could use .values('id', 'item__ref_id', ...)
for all fields in ItemDue
but that would be a lot of work. Is there a simple way I can append to the values of a queryset to get that reference object, without spelling out ALL the fields in the ItemDue
along with just the one extra field item__ref_id
?
Thanks
EDIT:
Here is some code run in the manage.py shell:
def check():
start = datetime.now()
print "Starting {0}".format(datetime.now() - start)
index = 0
item_rows = dict()
print "Getting Items for PG and Parents {0}".format(datetime.now() - start)
# items due for PG
items = pg.item_due.all().filter(disabled=False).select_related()
# Loop the parents, and chain their items due to the PG items due.
for p in parents:
items = itertools.chain(items, p.item_due.all().filter(disabled=False).select_related())
index += 1
print "All Items Retrieved {0}".format(datetime.now() - start)
for item in items:
pass
print "Loop Items Complete {0}".format(datetime.now() - start)
return item_rows
>>> rows = check()
Starting 0:00:00.000008
Getting Items for PG and Parents 0:00:00.000032
All Items Retrieved 0:00:00.004669
Loop Items Complete 0:00:00.022597
Notice the time it takes to loop the items and just pass
is about .018 seconds.
Now I simply change the pass
in the loop to item.item.ref_id
and it takes a LOT longer.
def check():
start = datetime.now()
print "Starting {0}".format(datetime.now() - start)
index = 0
item_rows = dict()
print "Getting Items for PG and Parents {0}".format(datetime.now() - start)
# items due for PG
items = pg.item_due.all().filter(disabled=False).select_related()
# Loop the parents, and chain their items due to the PG items due.
for p in parents:
items = itertools.chain(items, p.item_due.all().filter(disabled=False).select_related())
index += 1
print "All Items Retrieved {0}".format(datetime.now() - start)
for item in items:
item.item.ref_id
print "Loop Items Complete {0}".format(datetime.now() - start)
return item_rows
>>> rows = check()
Starting 0:00:00.000007
Getting Items for PG and Parents 0:00:00.000031
All Items Retrieved 0:00:00.004712
Loop Items Complete 0:00:00.258209
From .018 seconds to run the loop to .25 seconds. Why does it take 13 times the time just to process the item.item.ref_id if it is getting it from the query already?
Retrieving Single Objects from QuerySets We can do this using the get() method. The get() returns the single object directly. Let's see the following example. As we can see in both examples, we get the single object not a queryset of a single object.
A QuerySet is a collection of data from a database. A QuerySet is built up as a list of objects. QuerySets makes it easier to get the data you actually need, by allowing you to filter and order the data.
annotate() that has been computed over the objects that are related to the objects in the QuerySet . Each argument to annotate() is an annotation that will be added to each object in the QuerySet that is returned. The aggregation functions that are provided by Django are described in Aggregation Functions below.
Use select_related to get related tables data in one query:
for item_due in ItemDue.objects.filter(some_criteria).select_related():
print item_due.item.ref_id
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With