Reputation: 773
What is the best approach in a following situation?
Say we have some models, e.g. Article
, Photo
, BlogEntry
and so on. Every model can be displayed on the page as a thumb or a so-called widget.
Example:
thumbview
of a model contains item thumb with title in html blocknormalview
- contains larger thumb, title and description in a blockbigview
- thumb, title, description and say... number of comments adddedAll of these should be in some way polymorphic in a template so I could do something like iterating through my list of abstract items (various types) and simply:
{{ item.thumbview }}
or
{{ item.bigview }}
to display every item thumb.
It can be achieved lazy-evaluated in a model but I don't feel hardcode'ing html in a model is the right way.
How can I model such a behaviour? What is the best way?
I would appreciate any suggestion. Thanks.
Upvotes: 1
Views: 233
Reputation: 36453
You can use a custom template tag and a standard method in a model to give a context to the widget in case you can't achieve some properties in a template:
myapp/models.py
:
class Photo(models.Model):
...
def widget_context(self, context): # receives the context of the template.
user = context['request'].user # context should be RequestContext to contain request object (or you may use thread locals).
return {'tags': self.tag_set.filter(...), 'can_edit': self.owner == user or user.is_admin}
template tags file, widgets_app/templatetags/objwidgets.py
:
@register.simple_tag(takes_context=True)
def object_widget(context, obj, size='small'):
context_func = getattr(obj, 'widget_context') # try getting the context method
extra_context = context_func(context) if context_func else {}
extra_context['obj'] = obj
long_tuple = (obj._meta.app_label, 'widgets', obj.__class__.__name__, size)
return render_to_string([ # multiple templates to have both generic and specific templates
'%s/%s/%s.%s.html' % long_tuple, # the most specific (photos/widgets/photo.small.html)
'%s/widget.%s.%s.html' % (obj._meta.app_label, obj.__class__.__name__, size),
'%s/widget.%s.html' % (obj._meta.app_label, size), # myapp/widget.small.html
'widget.%s.html' % size,
],
extra_context
context)
usage:
{% load objwidgets %}
{% object_widget photo1 'large' %}
{% object_widget photo2 %}
make a template for the object widget, myapp/widgets/photo.small.html
:
<b>{{ obj.name }}</b>
<img src="{{ obj.thumbnail.url }}"/>
{% if can_edit %}<a href="{{ obj.get_edit_url }}">edit</a>{% endif %}
{% for t in tags %}
<a href="{{ tag.get_absolute_url }}">{{ tag.text }}</a>
{% endif %}
Upvotes: 1
Reputation: 53971
You shouldn't generate html at all in your model. You can write some custom template tags to achieve what you need. If you are using django dev version, you can create an inclusion tag with an argument that could return a piece of html depending on the model type of the input.
Upvotes: 0