#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 в зависимости от типа модели ввода.