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 ItemDues 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 ItemDues. 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?