I have a model tree, and use model to recursive render by itself using custom template tag.
Every Widget model own template and context data, and can be rendered by itself. Widget maybe have child widget model, child widget will be rendered first, parent widget can assemble them.
And template use custom tag.
Model code
class Widget(models.Model):
slug = models.SlugField(max_length=255, unique=True)
title = models.CharField(max_length=50, blank=True)
sub_title = models.CharField(max_length=50, blank=True)
parent = models.ForeignKey('self', null=True, blank=True,
related_name='widget', verbose_name=u'')
position = models.PositiveSmallIntegerField(default=1);
links = models.ManyToManyField(Link)
template = models.FilePathField(
path='templates/widgets/',
match='.*.html$', choices=WIDGETS_TEMPLATE, blank=True)
content = models.TextField(default="{}")
objects = WidgetManager()
def __unicode__(self):
return self.title
def get_template(self):
return path.join(settings.PROJECT_PATH, self.template)
def get_content(self):
return self.content
def get_template_slug(self):
return self.template.split('/')[-1][:-5]
def get_content_json(self):
# return self.encodeContent()
return json.loads(self.content)
Tag code
class WidgetNode(template.Node):
def __init__(self, position):
self.template = 'widgets/index-cools-subs.html'
# print template.Variable(self.positon)
self.position = template.Variable(self.position)
def render(self, context):
widgets = context['widgets']
attrs = {}
for widget in widgets:
if widget.position == self.position:
children = Widget.objects.filter(parent=widget)
if children:
attrs['widgets'] = [child for child in children]
else:
attrs = widget.get_content_json()
self.template = widget.get_template()
return render_to_string(self.template, attrs)
def widget(parser, token):
try:
tag_name, position = token.split_contents()
except ValueError:
msg = 'widget %s value error.' % token
raise template.TemplateSyntaxError(msg)
return WidgetNode(position)
Template code
<div class="section" name="subs" fd="index">
{% for widget in widgets %}
{% widget widget.position %}
{% endfor %}
</div>
I have two issues:
Any advice is much appreciated.
Thanks.
Django only executes the __init__
when "building" the template, when rendering only render()
is called. Therefore you need this fiddling using template variables, when doing something like self.position = template.Variable(self.position)
you tell Django only that self.position
is a variable defined in the template's context, but not its value; to get the value you need to resolve it when rendering:
def render(self, context):
position = self.position.resolve(context)
# do something with position...