about select_related() caching
I am doing a select_related() queryset to prevent hit database innecesarily. In my model I have:
class Item(models.Model)
user = models.ForeignKey(User, related_name='items')
name = models.CharField(max_length=255)
region = models.ForeignKey(Region, null = True, blank = True) #django-cities
country = models.ForeignKey(Country, null = True, blank = True) #django-cities
def get_ubicacion_name(self):
if self.region:
return self.region
else:
return self.country
class Activity(models.Model)
date = models.DateField()
item = models.ForeignKey(Item, related_name='items')
In my view:
ax = Activity.objects.select_related('item','item__region','item__country').all()[:40]
In my template:
{% for a in ax %}
{{ a.date }} - {{ a.get_ubicacion_name }}
{% endfor %}
debug tool bar displays 43 queries in 53.8开发者_如何学Go7ms
because is hitting self.country
so select_related('item','item_region','item_country')
is not working for this def?
In shell:
>>> ac = ax[0]
>>> dir(ac)
...... '_item_cache', .......
>>> dir(ac.item)
...... '_country_cache','_region_cache',.......
thank you.
This should work. Can you try it in the shell? Get the ax
queryset as you do in the view, then examine the first member with dir
:
>>> ac = ax[0]
>>> dir(ac)
One of the attributes you should see is _item_cache
, which is the way Django caches the ForeignKey lookup. Similarly, if you do dir(ac.item)
you should see entries for _region_cache
and _country_cache
. If not, post the results here and hopefully we can debug further.
I think the issue is that the cities are also related to regions and countries:
class City(models.Model):
# snip
region = models.ForeignKey(Region)
# snip
def __unicode__(self):
return "%s, %s" % (self.name, self.region)
and when you call get_ubicacion_name()
if the item has an associated city then the City.__unicode__()
method gets called which generates at least one new query (to find the region) for each item.
I'd change your select_related
as follows:
ax = Activity.objects.select_related(
'item','item__region__city__country','item__country'
).all()[:40]
I haven't tested this but I think it should work.
精彩评论