I'm having an issue where my templates are taking a really long time to load, and it looks like the problem is that a lot of database calls are made inside the template. This seems like it would be easy enough to fix, but I have kind of an odd setup with my model relationships that seems to be adding extra complexity.
The application is more or less a blog with multiple types of posts-- articles, book reviews, etc. Each of the post-type models is subclassed from a base model called Node. The base class contains the fields for things like the node title, author, creation date, and comment FKs, where the subclass contains the fields for things specific to the post type--body text, external URLs, start and end dates, etc. Additionally, I'm using the django-tagging app, with the tagging fields being located in the Node class. However, because of the way that the tagging app works, the M2M relationships seem to be formed with the subclass instance rather than the base class instance. Let's make this a bit more concrete: class Node(models.Model): author = models.ForeignKey(User) created = models.DateTimeField() published = models.BooleanField() promoted = models.BooleanField() section = models.ForeignKey(Section) archetype = models.ForeignKey(Archetype) title = models.CharField(max_length=255) slug = models.SlugField(max_length=25) comments_enabled = models.BooleanField() tag_list = models.CharField(max_length=255) def _get_tags(self): return Tag.objects.get_for_object(self) def _set_tags(self, tag_list): Tag.objects.update_tags(self, tag_list) tags = property(_get_tags, _set_tags) def get_absolute_url(self): return ('sake.node.views.node_detail', (), { 'sect': self.section.keyword, 'yr': self.created.year, 'mo': self.created.strftime('%m'), 'slg': self.slug}) get_absolute_url = models.permalink(get_absolute_url) def save(self): self.archetype = Archetype.objects.get(classname=type (self).__name__) if len(self.slug) == 0: self.slug = re.sub('\W', slugrepl, self.title.lower().strip())[: 25] super(Node,self).save() self.tags = self.tag_list def _comment_count(self): return self.comment_set.count() comment_count = property(_comment_count) class Article(Node): body = models.TextField() A typical view returns all of the nodes within a given section: def node_section_all(request, sect): try: objects = Node.objects.filter(section__keyword=sect, published=True).order_by('-created') except: return render_to_response('doesntexist.html', {'identifier': 'node'}, context_instance=RequestContext(request)) if len(objects) == 0: return render_to_response('doesntexist.html', {'identifier': 'node'}, context_instance=RequestContext(request)) return list_detail.object_list( request, queryset = Node.objects.filter(section__keyword=sect, published=True).order_by('-created'), template_name = 'node/section_list.html', allow_empty = True, paginate_by = 10, ) The main template calls a custom template tag in order to figure out what type of node is being rendered and pulls the appropriate template for that subclass: {% extends "base.html" %} {% load tags %} {% block content %} {% for node in object_list %} {% render_node node user %} {% endfor %} <div id="pager">{%comment%}{% pager 9 %}{%endcomment%}</div> {% endblock %} Where render_node looks like this: def render_node(node, user): from django.contrib.contenttypes.models import ContentType c = ContentType.objects.get(model = node.archetype.classname.lower ()) template_name = c.app_label + '/' + node.archetype.classname.lower() + '_detail.html' edit = False if user.is_authenticated(): if user.is_superuser or user.groups.filter (name=node.section.keyword).count(): edit = True return render_to_string(template_name, {'node': node, 'user': user, 'edit': edit}) register.simple_tag(render_node) And in the case of the Article subclass, this is the template used to render each node: <div class="node"> <h1>{{ node.title }}</h1> <div class="node-body"> {{ node.article.body|safe }} </div> <div class="node-footer"> Posted on {{ node.created|date:"F j, Y" }} by {% if node.author.get_profile %}<a href="{% url sake.accounts.views.display_profile username=node.author.username %}"> {{ node.author.get_profile.display_name }}</a>{% else %} {{ node.author.username }}{% endif %} in <a href="{% url node.views.node_section_all sect=node.section.keyword %}"> {{ node.section.section }}</a>{% if node.article.tags %} ({% for tag in node.article.tags %}{% if forloop.last %}<a href="{% url node.views.node_section_tag sect=node.section.keyword,tag=tag.name| slugify %}">{{ tag }}</a>{% else %}<a href="{% url node.views.node_section_tag sect=node.section.keyword,tag=tag.name| slugify %}">{{ tag }}</a>, {% endif %}{% endfor %}){% endif %}. | <a href="{% url node.views.node_detail sect=node.section.keyword,yr=node.created.year,mo=node.created| date:"m",slg=node.slug %}">Permalink</a> | <a href="{% url node.views.node_detail sect=node.section.keyword,yr=node.created.year,mo=node.created| date:"m",slg=node.slug %}#comment_start">{{ node.comment_count }} comment{% ifnotequal node.comment_count 1%}s{% endifnotequal %}</a>{% if edit %} | <a href="{% url article.views.edit_article sect=node.section.keyword,id=node.id %}">Edit</a> | <a href="{% url node.views.delete_node sect=node.section.keyword,id=node.id %}">Delete</a>{% endif %} </div> </div> As you can see, just about everything displayed needs to reference an FK in the end template, and then this is iterated many times over the entire set of nodes. One easy thing I can do is add select_related() to the queryset in the view, and that does help some. But things are still quite slow, taking 4 to 6 seconds to render the template. The culprits seem to be the for loop in the template that iterates over node.article.tags and also the two calls to node.comment_count. As you can see from the model, node.comment_count is a member function that returns the value of node.comment_set.count, and it looks like that isn't being evaluated until the template is rendered. What it looks like I need is to get my code to do more eager fetching, but I'm not sure exactly how to go about doing that. Does anyone have any thoughts? Thanks. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~----------~----~----~----~------~----~------~--~---