laszchamachla
laszchamachla

Reputation: 773

Generic templates or templates in models - Django

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:

All 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

Answers (2)

culebrón
culebrón

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

Timmy O&#39;Mahony
Timmy O&#39;Mahony

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

Related Questions