开发者

about select_related() caching

开发者 https://www.devze.com 2023-02-07 15:09 出处:网络
I am doing a select_related() queryset to prevent hit database innecesarily. In my model I have: class Item(models.Model)

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消