Web-приложение на django

Короткая версия: я хотел бы, чтобы один и тот же тип cmsplugin использовал разные шаблоны в разных заполнителях. Это возможно? Или я должен пойти и сделать свой собственный плагин?

Длинная версия: используя Django и Django-CMS и используя , у меня есть два видеоролика на домашней странице, и они стилизованы с использованием сетчатой ​​системы Foundation 4, которая будет укладываться в одну, а затем другую под ней и при определенном «точка прерывания» ширины браузера, они будут бок о бок. Все это хорошо работает.

Теперь я хотел бы добавить неограниченное количество видеороликов YouTube в другое который находится на другой странице, которая имеет другой шаблон. И я хотел бы, чтобы они отображали один ниже первого и так далее и на определенной «точке разлома» ширины браузера, они будут горизонтальными бок о бок, одна пара ниже первой и так далее.

Поскольку эти видеоэлементы YouTube имеют неограниченный, а не предопределенный номер, я не могу использовать сетку. Я решил, что я буду использовать системную сетку . Это позволяет мне создавать элементы как элементы внутри элемента . Это требует, чтобы я изменил шаблон для чтобы отобразить те элементы вокруг YouTubes. Проблема в том, что если я переопределю шаблон для этого плагина, предоставив , он также переопределит его и изменит его для экземпляров этого плагина, которые находятся на главной странице. И я люблю их такими, какие они есть.

Так что я думал, что было бы полезно иметь способ переопределить шаблон для плагина только для конкретного . Это позволило бы мне указать рендеринг YouTube в конкретном на моей другой странице и не влиять на экземпляры этого плагина на моей домашней странице, которые мне нравятся, как они есть.

Есть ли такой вариант — переопределить шаблон плагина для конкретного ?

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

Другой подход состоял бы в том, чтобы попытаться выполнить итерацию по экземплярам экземпляра плагина и визуализировать их с помощью целой вещи вокруг них один за другим. Я спросил об этом подходе, и, согласно некоторым ответам, мне показалось, что это не самый простой маршрут.

Каким будет ваш подход к этому, пожалуйста?

Я еще не получил ответа. Пожалуйста, даже указатель был бы чем-то!

Шаблоны

Создание и использование шаблонов

Последнее обновление: 21.02.2018

Шаблоны (template) отвечают за формирование внешнего вида приложения. Они предоставляют специальный синтаксис, который позволяет внедрять данные в код HTML.

Итак, в прошлых темах был создан следующий проект:

Проект называется hello. И в нем определено одно приложение — firstapp.

Теперь добавим шаблоны. Для этого определим в корневой папке проекта новый каталог templates. Вообще само имя каталога может быть любым, но, как правило, это именно templates. Теперь нам надо указать, что этот каталог будет использоваться в качестве хранилища шаблонов. Для этого откроем файл settings.py. В этом файле настройка шаблонов произодится с помощью переменной TEMPLATES:

TEMPLATES = [ { ‘BACKEND’: ‘django.template.backends.django.DjangoTemplates’, ‘DIRS’: [], ‘APP_DIRS’: True, ‘OPTIONS’: { ‘context_processors’: [ ‘django.template.context_processors.debug’, ‘django.template.context_processors.request’, ‘django.contrib.auth.context_processors.auth’, ‘django.contrib.messages.context_processors.messages’, ], }, }, ]

Параметр DIRS задает набор каталогов, которые хранят шаблоны. Но по умолчанию он пуст. Теперь изменим данный кусок кода следующим образом:

TEMPLATE_DIR = os.path.join(BASE_DIR, «templates») TEMPLATES = [ { ‘BACKEND’: ‘django.template.backends.django.DjangoTemplates’, ‘DIRS’: [TEMPLATE_DIR,], ‘APP_DIRS’: True, ‘OPTIONS’: { ‘context_processors’: [ ‘django.template.context_processors.debug’, ‘django.template.context_processors.request’, ‘django.contrib.auth.context_processors.auth’, ‘django.contrib.messages.context_processors.messages’, ], }, }, ]

Затем в папке templates определим новый файл index.html со следующим кодом:

<!DOCTYPE html> <html> <head> <meta charset=»utf-8″ /> <title>Hello Django</title> </head> <body> <h1>Welcome to Django!</h1> </body> </html>

По сути это обычная веб-страница, которая содержит код html.

Создание сайта на Django CMS

Теперь используем эту страницу для отправки ответа пользователю. И для этого перейдем в приложении firstapp к файлу views.py, который определяет функции для обработки запроса.

Изменим этот файл следующим образом:

from django.shortcuts import render def index(request): return render(request, «index.html»)

Из модуля импортируется функция render.

Функция index вызывает функцию render, которой передаются объект запроса request и путь к файлу шаблона в рамках папки templates — «index.html».

В файле urls.py в главном проекте пропишем сопоставление функции index с запросом к корню веб-приложения:

from django.contrib import admin from django.urls import path from firstapp import views urlpatterns = [ path(», views.index), ]

И запустим проект на выполнение и перейдем к приложению в браузере:

Таким образом, мы можем передавать в шаблоны данные и возвращать пользователю динамически генерируемые веб-страницы.

Однако в проекте Django нередко бывает несколько приложений. И каждое из этих приложений может иметь свой набор шаблонов. Чтобы разграничить шаблоны для отдельных проектов, можно определять для шаблонов каждого приложения отдельный каталог. Например, в нашем случае у нас одно приложение — firstapp. Для него определим в папке templates каталог firstapp (по имени приложения). И в этом каталоге определим также файл home.html:

<!DOCTYPE html> <html> <head> <meta charset=»utf-8″ /> <title>Hello Django</title> </head> <body> <h1>Hello from Home.html!</h1> </body> </html>

Теперь изменим файл views.py в приложении:

from django.shortcuts import render def index(request): return render(request, «firstapp/home.html»)

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

TemplateResponse

Выше для генерации шаблона применялась функция render(), которая является наиболее распространенным вариантом. Однако также мы можем использовать класс TemplateResponse:

from django.template.response import TemplateResponse def index(request): return TemplateResponse(request, «firstapp/home.html»)

Результат будет тот же самый.

НазадСодержаниеВперед

С давних пор программисты стараются отделить функциональную часть сайта от визуальной. На решение этой проблемы были созданы различные шаблонизаторы, которые выполняют роль отделения одной части сайта от другой. В языке Питон такой шаблонизатор называется Jinja.

Возможности этого шаблонизатора достаточно большие. Он способен не просто выводить HTML код, но также выполнять некоторые задачи Python, например: проверка условий, вывод через цикл, создание переменных и много других полезных вещей.

Ранее для вывода информации мы использовали HttpResponse, но это совсем не правильный подход к созданию сайтов.

Архитектура шаблонов Django

Вместо простого HTML мы будем использовать метод , который позволяет выводить HTML-шаблон. 

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

Все шаблоны хранятся в различных приложениях в папке templates. Django автоматически объединяет всех их в одну папку. Поэтому, если у вас будут два файла с одинаковым именем, то это вызовет ошибку. Чтобы избежать этого стоит помещать все шаблоны в еще одну дополнительную папку, которую стоит называть по имени вашего приложения.

Далее можно создать некий HTML файл, в который поместить немного Jinja логики:

Мы можем заменить содержимое на какой-либо другой файл. Для этого в другом файле необходимо указать что мы наследуем этот HTML файл и указать чем конкретно мы заменим содержимое:

Кроме того, мы можем создавать небольшие кусочки кода и встраивать их в другие шаблоны. Для таких кусочков лучше всегда создавать отдельную папку, которую можно назвать как . В ней можно создать простой HTML файл с небольшой Jinja разметкой:

Для подключения таких файлов используйте директиву include:

Домашнее задание

Необходимо оформить подписку на проект, чтобы получить доступ ко всем домашним заданиям!

Большое задание по курсу

Вам необходимо оформить подписку на сайте, чтобы получить большое задание. Такие задания есть к каждому курсу. В них входит задание, методика решения, а также «Готовое решение».
PS: подобные задания доступны только при подписке от 1 месяца!

ПредыдущийСледующий

Также стоит посмотреть

Я решил поделиться структурой, которую я использую для шаблонов. Я ее использую как в новых проектах, так и при реструкторизации уже существующих приложений. Этот процесс направлен на получение повторно используемых приложений с сохранением гибкости. Эта структура родилась постепенно в ходе многих тысяч часов работы с шаблонами и является удобной для меня. Ваши предпочтения могут отличаться. И вы же знакомы с организацией шаблонов в поддиректориях приложений? Верно?

Перед тем, как начать, я хотел бы показать одно из моих Django приложений с шаблонами. Gazette — приложение-блог (да, еще одно), над которым я работал и которое я буду использовать в качестве примера в данной статье.

Знайте ваши шаблоны

Первый принцип процесса разработки моих шаблонов пришел прямиком из The Zen of Python:

Читаемость имеет значение. В проектировании структуры шаблонов это означает, что достаточно бросить взгляд на директорию шаблонов, чтоб мгновенно понять для каких целей служит тот или иной шаблон. И что более важно, когда ко мне приходит клиент с изменениями в его приложении, мне не нужно разбираться в каком файле находиться необходимый код. Поиск должен затрагивать не более двух шаблонов. В итоге я разделил все свои шаблоны на три общие категории: расширяемые шаблоны, включаемые шаблоны и шаблоны страниц.

Расширяемые шаблоны

Расширяемые шаблоны формируют основную структуру ваших HTML страниц. Это шаблоны, основная цель которых быть расширенными другими шаблонами с помощью тега {% extends %}. Чтоб избежать перемешивания расширяемых шаблонов с шаблонами страниц я принял за правило никогда не вызывать расширяемые шаблоны напрямую из кода представлений (view) и никогда не расширять шаблоны, которые не являются расширяемыми. По соглашению о наименовании, я начинаю все свои расширяемые шаблоны с двойного подчеркивания: __base.html. Самым важным шаблоном является __base.html, который содержит скелет HTML для всех ващих страниц. Обычно этот шаблон делается минимальным. У меня он обычно выглядит следующим образом:

Как вы можете заметить, я использую Bootstrap для новых проектов, но этот же подход справедлив и для проектов без Bootstrap. Когда я пишу базовый шаблон, я стараюсь делать это осторожно. Я думаю: “Когда другой программист (включая меня через полгода) прийдет в этот проект и ему понадобится создать новый шаблон, могу ли я быть уверенным, что он сможет сделать любой шаблон не меняя базовый”. Результат оборачивается большим кол-вом тегов {% block %}, которые можно переопределить или расширить при необходимости. О теге {% block %} поговорим чуть позже. Если у вас очень простое приложение, то вам многое не нужно из того, что может предоставить __base.html для вашей структуры. И вы можете перейти к написанию шаблонов страниц и включаемых шаблонов. Но если ваше приложение достаточно сложное, то вам может понадобиться создать несколько различных структурных шаблонов (layout templates). В Gazette я использую три структурных шаблона, имена которых начинаются с __l_ (и снова их назначение определяется мгновенно из названия): __l_single_col.html, __l_right_sidebar.html, __l_left_sidebar.html. Я храню их в одной директории с остальными шаблонами согласно принципу:

Плоское лучше, чем вложенное

С другой стороны, если вам необходимо более трех шаблонов, то вы можете поместить их в поддиректорию layouts/. Когда я работаю над проектов с очень сложной сеткой, то часто создаю такую поддиректорию с шаблонами: layouts/100.html, layouts/25_75.html, layouts/50_50.html и т.д. Например один из моих структурных шаблонов, __l_right_sidebar.html :

Это очень простой шаблон — настолько простой, что может показаться, что он и не нужен. Но, поверьте мне, этот маленький шаблон предоставляет множество преимуществ при создании ваших шаблонов страниц.

Включаемые шаблоны

Включаемые шаблоны — это шаблоны, которые планируете включать в шаблоны страниц с помощью тега {% include %}. Как и с расширяемыми шаблонами я строго слежу за применением включаемых шаблонов. Вы можете рассматривать их и как некие блоки, из которых строится ваш сайт, собираясь в шаблоне страницы. Есть две основные причины сделать часть вашего сайте включаемым:

  • вы планируете использовать этот модуль повторно на многих страницах и вы хотите сохранить чистоту кода.
  • вы хотите предоставить другому разработчику возможность переопределить этот модуль в вашем приложении без вмешательства в структуру вашего шаблона.

И как всегда, разрабатывайте продуманно: будьте готовы, что другие разработчики (включая вас через полгода) захотят изменить или переопределить ваши шаблоны так, как вы даже не можете представить. Но следите за балансом. Слишком мало включаемых блоков дает мало возможностей для модификации, что раздражает, а слишком много — создает спагетти код, в котором сложно ориентироваться.

Шаблоны страниц

Шаблоны страниц — ядро вашего приложения. Но если вы перед этим создали несколько хороших расширяемых шаблонов и возможно даже несколько включаемых, то вы заметите насколько просто связать все вместе. Это просто клей, который связывает ваши шаблоны вместе. Ваши шаблоны страниц — это именно то, что вызывается из кода представлений (views). Они гармонично связывают расширяемые и включаемые вместе. Например, article_detail.html :

Как вы видете, эта страница использует __l_right_sidebar.html.

Разработка своего плагина для Django-CMS

Главная колонка содержит полный текст статьи. Боковая колонка содержит список тегов и список категорий. Этот шаблон настолько легко читаем, насколько возможно. Я упоминал, что выделение отдельного уровня шаблонов структуры приведет к увеличению возможностей и это так. Если вы решите, что список тегов и категорий лучше расположить в левой колонке, то вам достаточно будет лишь поменять первую строку шаблона article_detail.html на:

и содержимое переместится именно туда, куда надо.

Дальше больше. Если другой разработчик предпочитает структуру 75% — 25% вместо 66% — 33%, которую использую я в __l_right_sidebar.html, то от может переопределить шаблон:

и все страницы, которые его используют, изменятся нужным образом. Согласно принятому соглашению о названиях, когда это возможно, я стараюсь следовать соглашению об именях, принятому в Django generic views, т.е. _list.html, _detail.html, _form.html и т.д. Если шаблон не попадает под эти категории, то просто старайтесь давать ему название, четко определяющее то представление (view), к которому он относится.

Заметки о {% block %} и {{ block.super }}

Система наследования шаблонов в Django удивительно мощная и тут очень просто увлечься. Я часто вижу как в базовых шаблонах (т.е. расширяемых) разработчики пишут контент по-умолчанию в блоках:

предполагая, что он будет переопределен при расширении данного шаблона в других страницах. Я хочу предостеречь вас от использования этого подхода, т.к. он смешивает ваши расширяемые шаблоны с шаблонами страниц и становиться сложнее находить то месно, которое нужно изменить в каждом конкретном случае. (“Где это ? В frontpage.html или в base.html?”). Вместо этого рассматривайте содержимое блоков в расширяемом шаблоне как текст, который может быть использован в разных шаблонах страниц с помощью {{ block.super }}. Простейший пример — это элемент страницы < title > . Я часто вижу следующую структуру в базовом шаблоне:

Это не только кажется мне не элегантным (Куда нужно поместить разделитель между заголовком страницы и заголовком сайта, т.е. “Заголовок страницы | Заголовок сайта” — в базовый шаблон или в шаблон страницы? А как быть со страницами, которым не нужен заголовок ?), но и ограничивает разработчика в том, что он может сделать без внесения изменений в базовый шаблон. И я гораздо реже вижу более простую структуру:

Аналогично с css или другими включениями:

или, боже упаси,

Это запутаннее и избыточнее, чем простое:

Позже в ваших шаблонах страниц вы можете добавить другие стили следующим образом:

Аналогично и с заголовком:

Это, на мой взгляд, элегантнее — блоки лучше названы, их меньше, они более точно выражают структуру — и если вы захотите отказаться от заголовка по-умолчанию или стилей по-умолчанию, не отказываясь от всего базового шаблона, вы свободно можете это сделать. {{ block.super }} — очень мощная штука. Используйте ее внимательно.

Несколько заметок на последок

Интернационализация

Пожалуйста, используйте интернационализацию ваших шаблонов. Особенно, если вы пишите приложения для повторного использования. Это очень просто с использованием тегов {% trans %} и {% blocktrans %}.

{% include %} и {% with %}

Довольно долгое время я писал ужасный код наподобее этого:

До тех пор, пока не заметил [удобный синтаксис], который доступен с версии Django 1.3:

Для дополнительной инкапсуляции, попробуйте передать в ваши включаемые шаблоны эксклюзивный контекст:

Закрывающиеся теги HTML и язык шаблона Django по своей природе — вложенный, что иногда снижает читаемость.

Особенно при работе с большими блоками. Язык шаблонов Django имеет дополнительный необязательный синтаксис, который помогает отслеживать ваши блоки:

А в других случаях? Я часто использую комментарии для имитации этого для других тегов шаблона и HTML:

что, как я заметил, сильно повышает наглядность кода.

Обрабатывайте HTML и теги шаблона одинаково

Я всегда считал, что отступы для HTML тегов должны обрабатываться отдельно от отступов тегов шаблона. Возможно это ошибочное мнение было основано на том, что структура результирующего HTML кода имеет большее значение. Это все приводило к тому, что большое количество кода имело вид:

Этот код можно сделать более читабельным, если рассматривать теги HTML и теги шаблона как равноправные:

Это ли не достаточная причина?

Оригинал: Architecture for Django templates

comments powered by

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *