At risk of hijacking the thread, I've been struggling with something
similar (if I understand patrick correctly) Basically, I've been trying
to come up with a way of including re-usable 'pagelets' or
sub-templates into a parent template that are rendered with their own
local context generated by generic (i.e. re-usable) code. Essentially
I've come up with two ways of doing this, both of which have issues.
The first way I've tried involves coding the pagelet as if it were a
full blown page - i.e. creating a template suitable for use with a
generic view, and connecting that to the generic view using a urlconf
in the normal way, so I can browse to a url and see the template
rendered - the app_label and module_name are passed into the generic
view in a dict, and parameters can be passed from the url - all
standard stuff. Then I've written a custom template tag, which takes a
constructed url as a parameter, resolves that url and returns the
rendered template. The code is below:
from django.core import template
from django.utils.httpwrappers import HttpRequest
from django.utils.httpwrappers import HttpResponse
from django.utils.httpwrappers import HttpResponseNotFound
from django.utils.httpwrappers import HttpResponseForbidden
from django.utils.httpwrappers import HttpResponseGone
from django.utils.httpwrappers import HttpResponseServerError
from django.core.handlers.base import BaseHandler
from django.parts.auth.anonymoususers import AnonymousUser
from django.models.auth import User
#usage: {% include_url %}/url/with/{{ param }}/{% end_include_url %}
def do_include_url(parser, token):
nodelist = parser.parse(('end_include_url',))
parser.delete_first_token()
return IncludeUrlNode(nodelist)
class IncludeUrlNode(template.Node):
def __init__(self, nodelist):
self.nodelist = nodelist
def render(self, context):
try:
self.request = HttpRequest()
self.request.path = self.nodelist.render(context)
self.request.META['HTTP_HOST'] = ''
self.request.META['REQUEST_METHOD'] = ''
self.request.META['REMOTE_ADDR'] = ''
if (context.has_key('user') and
isinstance(context['user'], User)):
self.request.user = context['user']
else:
self.request.user = AnonymousUser()
self.handler = BaseHandler()
self.handler.load_middleware()
self.response =
self.handler.get_response(self.request.path, self.request)
if (isinstance(self.response, HttpResponse) and
not isinstance(self.response, HttpResponseNotFound) and
not isinstance(self.response, HttpResponseForbidden)
and
not isinstance(self.response, HttpResponseGone) and
not isinstance(self.response, HttpResponseServerError)
and
isinstance(self.response.content, basestring)):
return self.response.content
else:
return ""
except:
return ""
register = template.Library()
register.tag('include_url', do_include_url)
This is OK, it would be better if it had access to the request object,
then it could prevent recursive calls (i.e. if you pass it the url of
the template that it's located in, you will generate an infinitely long
response as the tag is called recursively). It has the advantage that
it can use generic views, but it doesn't really feel right to configure
these pagelets with their own urls.
The alternative is to use the {% include %} tag to include an
unrendered template, which then loads and uses a template tag to
populate the context it needs to be rendered. It would in theory be
possible to write 'generic' template tags, which like the generic views
take 'app_label' and 'module_name' as parameters alongside any other
parameters. These would be re-usable, but getting the app_label and
module_name to them at the point they're called in the template is
tricky - you could hard code them into the template, but then the
template isn't re-usable anymore. Alternatively, you could try to pass
them in the context of the parent template, or load them with a custom
template tag which reads some form of configuration, but both of those
seem messy.
I'd be very interested in any other suggestions for ways to include
reusable templates that are rendered with context from reusable
(generic) code. Or suggestions for ways to improve my template tag code
above.