Why would Django (1.5.1) call Loader.load_template_source() 69 times? -
my problem manifested "maximum recursion depth exceeded" error in run-of-the-mill listview
. after digging around, found ton of cache hits originating in dbtemplates every attempt made load corresponding page. prompted me write own template loader, @ point became apparent django calling load_template_source
sixty-nine times every time page loaded.
why django call load_template_source
multiple times?
visitor_index (db template)
<!doctype html> <html lang="en"> <head> <title>{{ site.name }}</title> </head> <body id="home"> <pre> starting {% video in videos %} {{ video.headline }} {% endfor %} </pre> </body> </html>
urls.py
from django.conf.urls import include, url django.conf.urls.defaults import patterns videos.views import * urlpatterns = patterns('', url(r'^$', visitorindex.as_view(), name='index'), )
views.py
import logging django.views.generic import listview videos.models import video logger = logging.getlogger(__name__) class visitorindex(listview): context_object_name = 'videos' template_name = 'visitor_index' def get_queryset(self): logger.debug('visitorindex.get_queryset()') return video.on_site.filter(privacy_mode='pub')
loader.py
import logging django.template import templatedoesnotexist django.template.loader import baseloader dbtemplates.models import template logger = logging.getlogger(__name__) class loader(baseloader): is_usable = true def load_template_source(self, template_name, template_dirs=none): try: logger.debug('loader.load_template_source(%s, %s)' % (template_name, template_dirs)) template = template.on_site.get(slug__exact=template_name).template_body logger.debug('loaded template.') return template, template_name except template.doesnotexist: logger.debug('template.doesnotexist caught.') raise templatedoesnotexist, template_name
models.py
import logging django.contrib.sites.models import site django.contrib.sites.managers import currentsitemanager django.db import models logger = logging.getlogger('__name__') class template(models.model): slug = models.charfield(max_length=80) template_body = models.textfield() site = models.foreignkey(site) objects = models.manager() on_site = currentsitemanager('site') def __unicode__(self): return self.slug
settings.py
template_loaders = ( 'django.template.loaders.filesystem.loader', 'django.template.loaders.app_directories.loader', 'dbtemplates.loader.loader', )
app.log (updated trace)
2013-05-09 19:15:43,634 [debug] dynamicsites.middleware: env_hostnames lookup subdomain=none domain=mydomain.com domain_unsplit=mydomain.com 2013-05-09 19:15:43,634 [debug] dynamicsites.middleware: checking database domain=mydomain.com 2013-05-09 19:15:43,679 [debug] dynamicsites.middleware: using site id=2 domain=mydomain.com 2013-05-09 19:15:43,714 [debug] videos.views: visitorindex.get_queryset() 2013-05-09 19:15:43,716 [debug] django.template.response: simpletemplateresponse.rendered_content() 2013-05-09 19:15:43,717 [debug] django.template.response: start self.resolve_template() 2013-05-09 19:15:43,717 [debug] django.template.response: simpletemplateresponse.resolve_template(). found list or tuple. 2013-05-09 19:15:43,717 [debug] django.template.response: calling loader.select_template(template=['visitor_index', u'videos/video_list.html']) 2013-05-09 19:15:43,720 [debug] dbtemplates.loader: loader.load_template_source(visitor_index, none) 2013-05-09 19:15:43,722 [debug] dbtemplates.loader: file "/usr/lib/python2.7/threading.py", line 525, in __bootstrap self.__bootstrap_inner() file "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner self.run() file "/usr/lib/python2.7/threading.py", line 505, in run self.__target(*self.__args, **self.__kwargs) file "/usr/lib/python2.7/socketserver.py", line 593, in process_request_thread self.finish_request(request, client_address) file "/usr/lib/python2.7/socketserver.py", line 334, in finish_request self.requesthandlerclass(request, client_address, self) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/core/servers/basehttp.py", line 150, in __init__ super(wsgirequesthandler, self).__init__(*args, **kwargs) file "/usr/lib/python2.7/socketserver.py", line 649, in __init__ self.handle() file "/usr/lib/python2.7/wsgiref/simple_server.py", line 124, in handle handler.run(self.server.get_app()) file "/usr/lib/python2.7/wsgiref/handlers.py", line 85, in run self.result = application(self.environ, self.start_response) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/contrib/staticfiles/handlers.py", line 72, in __call__ return self.application(environ, start_response) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 255, in __call__ response = self.get_response(request) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 140, in get_response response = response.render() file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/template/response.py", line 121, in render self.content = self.rendered_content file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/template/response.py", line 91, in rendered_content template = self.resolve_template(self.template_name) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/template/response.py", line 60, in resolve_template t = loader.select_template(template) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/template/loader.py", line 188, in select_template return get_template(template_name) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/template/loader.py", line 146, in get_template template, origin = find_template(template_name) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/template/loader.py", line 135, in find_template source, display_name = loader(name, dirs) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/template/loader.py", line 43, in __call__ return self.load_template(template_name, template_dirs) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/template/loader.py", line 46, in load_template source, display_name = self.load_template_source(template_name, template_dirs) file "/home/wesley/howl/dbtemplates/loader.py", line 19, in load_template_source logger.debug(''.join(traceback.format_stack())) 2013-05-09 19:15:43,885 [debug] dbtemplates.loader: loaded template. 2013-05-09 19:15:43,886 [debug] django.template.response: done. 2013-05-09 19:15:43,887 [debug] django.template.response: done. <django.template.base.template object @ 0x7fbdf8215050> 2013-05-09 19:15:43,887 [debug] django.template.response: start self.resolve_context() 2013-05-09 19:15:43,920 [debug] django.template.response: start template.render(context) 2013-05-09 19:15:43,920 [debug] django.template.base: template.render(context) 2013-05-09 19:15:43,920 [debug] django.template.base: context.render_context.push() 2013-05-09 19:15:43,920 [debug] django.template.base: done. 2013-05-09 19:15:43,921 [debug] django.template.base: try self._render(context) 2013-05-09 19:15:43,932 [debug] dbtemplates.loader: loader.load_template_source(visitor_index, none) 2013-05-09 19:15:43,933 [debug] dbtemplates.loader: file "/usr/lib/python2.7/threading.py", line 525, in __bootstrap self.__bootstrap_inner() file "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner self.run() file "/usr/lib/python2.7/threading.py", line 505, in run self.__target(*self.__args, **self.__kwargs) file "/usr/lib/python2.7/socketserver.py", line 593, in process_request_thread self.finish_request(request, client_address) file "/usr/lib/python2.7/socketserver.py", line 334, in finish_request self.requesthandlerclass(request, client_address, self) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/core/servers/basehttp.py", line 150, in __init__ super(wsgirequesthandler, self).__init__(*args, **kwargs) file "/usr/lib/python2.7/socketserver.py", line 649, in __init__ self.handle() file "/usr/lib/python2.7/wsgiref/simple_server.py", line 124, in handle handler.run(self.server.get_app()) file "/usr/lib/python2.7/wsgiref/handlers.py", line 85, in run self.result = application(self.environ, self.start_response) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/contrib/staticfiles/handlers.py", line 72, in __call__ return self.application(environ, start_response) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 255, in __call__ response = self.get_response(request) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 140, in get_response response = response.render() file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/template/response.py", line 121, in render self.content = self.rendered_content file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/template/response.py", line 97, in rendered_content content = template.render(context) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/template/base.py", line 146, in render return self._render(context) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/test/utils.py", line 65, in instrumented_test_render return self.nodelist.render(context) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/template/base.py", line 837, in render bit = self.render_node(node, context) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/template/debug.py", line 74, in render_node return node.render(context) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/template/defaulttags.py", line 148, in render len_values = len(values) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/db/models/query.py", line 90, in __len__ self._result_cache = list(self.iterator()) file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/db/models/query.py", line 301, in iterator row in compiler.results_iter(): file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 775, in results_iter rows in self.execute_sql(multi): file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 840, in execute_sql cursor.execute(sql, params) file "/home/wesley/howl/debug_toolbar/utils/tracking/db.py", line 134, in execute template_info = get_template_info(node.source) file "/home/wesley/howl/debug_toolbar/utils/__init__.py", line 80, in get_template_info template_source = origin.reload() file "/home/wesley/environments/howl/local/lib/python2.7/site-packages/django/template/loader.py", line 80, in reload return self.loader(self.loadname, self.dirs)[0] file "/home/wesley/howl/dbtemplates/loader.py", line 19, in load_template_source logger.debug(''.join(traceback.format_stack())) [...]
i reproduced project without problem.
the loader called once without recursion. added simple necessary files: videos/models.py , videos/admin.py, dbtemplates/admin.py in order add 2 records video , 1 record template loops on videos: {% video in videos %}...{% endfor %}
i still can not believe recursion possible in loader.load_template_source()
. more information necessary. try traceback every call of loader adding these 2 lines it:
... logger.debug('loader.load_template_source......') import traceback # added logger.debug(''.join(traceback.format_stack())) ...
(i afraid loop or recursion originated in other code spawned many threads wait before database operation until running operation finished.)
edit: problem caused django-debug-toolbar.
- the database cursor wrapped debug_toolbar monitoring code.
- it tries introspect stack
template_info
of template usedrender
. - template_info uses template reloading.
- that again needs access database.
you can disable parts of debug toolbar related database or templates (not tested helps) or disable completely. database operations monitored django , same done debug toolbar less important now.
Comments
Post a Comment