Django: наследование видов при создании сайта
Итак, напомню, что виды в Django — основное средство формирования содержимого веб-страниц, которые представляются в виде обычных функций языка Python. Сейчас не буду вдаваться в подробности и описывать принципы работы видов, можно посмотреть официальную документацию (http://docs.djangoproject.com/en/1.3/topics/http/views/).
Допустим, стоит задача создать сайт, каждая страница которого состоит из двух частей: общей части (одинаково выглядит для всех страниц) и специальной части (разная для каждой страницы). То есть каждая специальная часть будет иметь собственный вид, который позаботится о выводе информации.
Первое, что может прийти в голову — воспользоваться средством наследования шаблона, которое описано в официальной документации Django (шаблон — это разметка страницы плюс специальные теги шаблонизатора Django).
В этом случае у Вас имеется общий шаблон, от которого нужно будет унаследовать шаблоны Ваших страниц.
Приведём для большей наглядности пример.
Вот так может выглядеть базовый шаблон:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> /> {% block title %}Мой замечательный сайт{% endblock %} {% block sidebar %} <ul> <li><a href="/">Главная</a></li> <li><a href="/freebsd">FreeBSD</a></li> </ul> {% endblock %} {% block content %}{% endblock %}
А так — один из шаблонов-наследников (страница FreeBSD):
{% extends "base.html" %} {% block title %}Мой замечательный блог FreeBSD{% endblock %} {% block content %} {% for entry in blog_entries %} <h2>{{ entry.title }}</h2> {{ entry.body }} {% endfor %} {% endblock %}
Шаблон был унаследован с помощью тега extends.
Какой явный недостаток предлагаемого метода? В примере базовому шаблону не передаётся параметров из вида. Причина проста — Вашему шаблону-родителю ничего не известно об упомянутых параметрах. Вида, который бы эти параметры ему передал — попросту нет. Конечно же, можно передавать эти параметры из вида, который привязан к шаблону-наследнику, но это не удобно. Придётся одни и те же параметры передавать из всех видов, ведь страниц-то может быть не одна. Это нарушило бы главный принцип платформы Django «DRY» («Don’t Repeat Yourself» — проще говоря, «не повторяйся»).
Предлагается следующее решение данной проблемы.
- Создаём родительский вид, родительский шаблон привязываем к нему.
- Родительский вид будет представлен не функцией, а классом.
- Дочерний вид также будет представлен классом, который наследует класс родительского вида. Кроме того, в дочернем виде будет в наличии входная функция, возвращающая контент страницы, которую можно будет прописать в обычном порядке в файле urls.py.
Вот пример данных классов.
Родительский:
from django.shortcuts import render_to_response
from django.template import Context, Template
from django.template.loader import get_template
class BaseParentView:
def __init__( self ):
self._baseViewTemplate = "parent.html"
def _renderChildTemplate( self, **params ):
template = get_template( self._childTemplate )
return template.render( Context( params ) )
def getView( self ):
text = "Текст из родительского вида, который попадёт в заголовок страницы"
return render_to_response( self._baseViewTemplate, { 'child_content': self._childContent, 'text': text } )
И сответствующий шаблон:
{{ text }}
{{ child_content }}
Дочерний:
from base_pass.parent.views import BaseParentView
class ChildView( BaseParentView ):
def __init__( self ):
BaseParentView.__init__( self )
self._childTemplate = "child.html"
def getView( self ):
text = u"Текст из дочернего вида, который будет размещаться в теле страницы"
self._childContent = self._renderChildTemplate( content = text )
return BaseParentView.getView( self )
# Та самая функция, которая вернёт контент страницы на основе дочернего
# класса
def child( request ):
child = ChildView()
return child.getView()
И дочерний шаблон:
{{ content }}
Функция, возвращающия контент в каждом классе, имеет имя getView, а соответствующие шаблоны прописаны в членах классов _baseViewTemplate и _childTemplate.
Таким образом, мы можем создавать дочерные классы и соответствующие шаблоны для каждой страницы Вашего сайта, а о передаче параметров в общую часть позаботится наш родительский класс.
При этом мы не использовали предлагаемый платформой Django тег наследования шаблонов extends.
Вы можете попробовать данный подход, создав тестовый проект Django. Не забудьте прописать в urls.py дочернего вида кортеж для функции child.