Общие шаблоны или шаблоны в моделях — Django

#django #django-templates

#django #django-шаблоны

Вопрос:

Каков наилучший подход в следующей ситуации?

Допустим, у нас есть некоторые модели, например Article , Photo , BlogEntry и так далее. Каждая модель может отображаться на странице в виде большого пальца или так называемого виджета.

Пример:

  • атрибут thumbview модели содержит элемент thumb с заголовком в блоке html
  • normalview — содержит большой палец, заголовок и описание в блоке
  • bigview — большой палец, заголовок, описание и сказать … количество добавленных комментариев

Все они должны быть каким-то образом полиморфными в шаблоне, чтобы я мог делать что-то вроде перебора моего списка абстрактных элементов (различных типов) и просто:

 {{ item.thumbview }}
  

или

 {{ item.bigview }}
  

для отображения каждого элемента большого пальца.

Это может быть достигнуто с помощью ленивой оценки в модели, но я не чувствую, что жесткое кодирование html в модели является правильным способом.

Как я могу смоделировать такое поведение? Каков наилучший способ?

Я был бы признателен за любое предложение. Спасибо.

Ответ №1:

Вы можете использовать пользовательский тег шаблона и стандартный метод в модели, чтобы задать контекст виджету в случае, если вы не можете достичь некоторых свойств в шаблоне:

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}
  

файл тегов шаблона, 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)
  

использование:

 {% load objwidgets %}
{% object_widget photo1 'large' %}
{% object_widget photo2 %}
  

создайте шаблон для виджета объекта, 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 %}
  

Комментарии:

1. После нескольких дней кодирования — этот подход просто потрясающий! Это отлично поощряет DRY, делает разработку более быстрой и чистой. Лучший совет Django по SO для меня когда-либо 🙂

Ответ №2:

Вы вообще не должны генерировать HTML в своей модели. Вы можете написать некоторые пользовательские теги шаблонов, чтобы достичь того, что вам нужно. Если вы используете версию django dev, вы можете создать тег включения с аргументом, который может возвращать фрагмент html в зависимости от типа модели ввода.