Evgenii Legotckoi
Evgenii Legotckoi5 июля 2018 г. 3:05

Django - Урок 035. Различные шаблоны для рендеринга разных типов контента в поисковой выдаче

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

Посмотрим на пример выдачи.

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

Но это сделано гораздо более изящно, чем выбор через if else . Честно, мне самому очень нравится это решение.


Для каждой модели данных нужно определить поле, которое хранит путь к шаблону для отображения объекта этой модели. При этом в каждой модели это поле должно иметь одно и тоже название. Это очень важно.

Например сделаем так

class Article(models.Model):
    TEMPLATE_PREVIEW = 'home/article_preview.html'

class Comment(models.Model):
    TEMPLATE_PREVIEW = 'home/comment_preview.html'

class Topic(models.Model):
    TEMPLATE_PREVIEW = 'home/topict_preview.html'

class Post(models.Model):
    TEMPLATE_PREVIEW = 'home/post_preview.html'

В каждом этом шаблоне мы можем прописать своё собственное отображение контента, которое на потребуется. Например для статьи

<div>
    <a href="{{ object.get_absolute_url }}"><h2>{{ object.itle }}</h2></a>
    {{ object.content|safe }}
    <p><a class="btn btn-default btn-sm" href="{{ object.get_absolute_url }}">Читать далее</a></p>
</div>

А для всех остальных шаблонов можем написать что-нибудь другое. Главное, чтобы все методы и поля, а также имя одиночного объекта было одинаковым во всех шаблонах.

А сам шаблон поисковой выдачи может выглядеть так

{% load tz %}
{% load trans from i18n %}
{% load bootstrap_pagination from bootstrap4 %}
<div id="object-list">
    {% for object in object_list %}
        {% include object.TEMPLATE_PREVIEW %}
    {% empty %}
        <div class="card card-body mb-3">{% trans 'Ничего не найдено' %}</div>
    {% endfor %}
    {% bootstrap_pagination object_list pages_to_show="10" url=last_question %}
</div>

Нюанс заключается в том, что мы привыкли передавать в тег include строковое имя шаблона, например так

{% include 'home/article_preview.html' %}

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

{% include object.TEMPLATE_PREVIEW %}

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

Для Django рекомендую VDS-хостинг TIMEWEB

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

bernar92
  • 5 июля 2018 г. 3:58

интересное решение! интересно как реализовать такое через

Django REST

Evgenii Legotckoi
  • 5 июля 2018 г. 4:12

К сожалению, я сейчас мало использую django_rest_framework , но в будущем планирую значительную часть работы сайта переводить на него. Поэтому придумаю какое-нибудь подобное решение с использованием какого-нибудь JS-шаблонизатора.

Илья Чичак
  • 16 июля 2018 г. 22:01

Идея с классовыми параметрами интересна, однако при большом количестве элементов, это может занять значительные время. И дело даже не в решении, а в тэге include. При его использовании, шаблон будет искаться для каждого использования без учёта того, что это один и тот же шаблон. Если выводится 50, 100 или сколько-нибудь адекватное количество элементов - можно жить, но надо помнить, что в этом месте можно неслабо так порезаться.

И ещё одна проблема, что шаблоны не грузятся в память при запуске сервера. Так что без какого-нибудь кэширования этих шаблонов можно упереться в рендеринг, как в узкое место.
Evgenii Legotckoi
  • 17 июля 2018 г. 2:31

Согласен с вами!

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


bernar92
  • 17 июля 2018 г. 2:57

через классовый метод не обойтись

bernar92
  • 17 июля 2018 г. 3:01

мне кажется лучше это сделать на стороне клиента где при помощи vue js! а в модель сделать свойство по которому js будет генерирывать шаблон

Evgenii Legotckoi
  • 17 июля 2018 г. 3:04

А я вот планирую внедрять nunjucks, он очень сильно похож по синтаксису на шаблоны Django, и также поддерживает наследование шаблонов. Пробный запуск я уже делал и весьма понравилось. Но пока не внедрял в качестве боевого варианта, есть ещё где развернуться по оптимизациям на стороне сервера.

Илья Чичак
  • 17 июля 2018 г. 3:43
Я тут поэксперементировал. И что-то у меня не особо получилось сделать inclusion_tag и сунуть указатель на него в классовую переменную.
Я думаю, можно чуть глубже погрузиться в механизм шаблонных тэгов и попробовать сделать один тэг, в который передается объект модели, а он выбирает нужный шаблон и рендерит его.

либо не греть голову и сделать несколько тэгов - для каждой модели. а в классе модели определить какую-то переменную (например однобуквенную:) ) по которой бы определялось, какой тэг использовать. а если этот механизм часто используется, код выбора нужного тэга сунуть в еще один шаблон и сделать inclusion_tag. получится длинная цепочка, и, возможно, немного запутанная, но получится достаточно быстро
bernar92
  • 17 июля 2018 г. 4:00

запутанная... уже что-то пугает ....

Evgenii Legotckoi
  • 17 июля 2018 г. 5:02

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

Также в качестве аргументов передавать в этот тег объект и имя параметра, а потом через getattr брать из объекта ту переменную... тогда получится один единственный тег для всех видов шаблонов, например TEMPLATE_PREVIEW, TEMPLATE_INFO и т.д.
Илья Чичак
  • 17 июля 2018 г. 5:29

Вообще, я полностью согласен. Подобное лучше всего отдать на откуп клиенту.

Илья Чичак
  • 17 июля 2018 г. 5:32

Запутанность - условная. Будет просто цепочка вызовов inclusion_tag-ов. Причём первое звено нужно лишь для возможности повторного использования. Если таковое не предполагается, можно опустить один уровень.

Evgenii Legotckoi
  • 17 июля 2018 г. 5:43

Думаю, что это всё равно стоит оставить для индексирующих роботов поисковых систем, которые испоьлзуют простые GET запросы. Они же AJAX не используют. Так что полностью уйти от этого не получится, если есть открытый контент на сайте.

Илья Чичак
  • 17 июля 2018 г. 5:53
тут все упирается в то, что вы хотите дать поисковым роботам. был у меня опыт проектирования страницы для роботов - сделал точки входа - со статикой для роботов и АПИ для JS клиента=) а отлавливал по UserAgent-у на уровне миддлвари (они особо не шифруются).
Если использовать JS, то можно и выводить порционно, подгружая новые объекты по мере скролла к концу текущего списка=) Тогда вообще нагрузки будет минимум. и отрисовывать будет моментально (при достаточно малых размеров порций данных).

А по поводу inclusion_tag-ов - не так просто заставить их работать из мета-программирования=( мне вот пришла в голову мысль, что можно было бы строить эти тэги в момент инициализации рантайма. тоесть где-то в templatetags модуле сканировать нужные модели, брать из них классовые переменные и на их основе создавать тэги. Но я бы поостерегся - очень много нюансов. и в первую очередь, можно очень быстро запутаться, а потом не разобраться=/

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:50баллов,
  • Очки рейтинга-4
m
  • molni99
  • 26 октября 2024 г. 11:37

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80баллов,
  • Очки рейтинга4
m
  • molni99
  • 26 октября 2024 г. 11:29

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:20баллов,
  • Очки рейтинга-10
Последние комментарии
ИМ
Игорь Максимов22 ноября 2024 г. 22:51
Django - Урок 017. Кастомизированная страница авторизации на Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii Legotckoi1 ноября 2024 г. 0:37
Django - Урок 064. Как написать расширение для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZE19 октября 2024 г. 18:19
Читалка fb3-файлов на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов5 октября 2024 г. 17:51
Django - Урок 064. Как написать расширение для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55 июля 2024 г. 21:02
QML - Урок 016. База данных SQLite и работа с ней в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Сейчас обсуждают на форуме
Evgenii Legotckoi
Evgenii Legotckoi25 июня 2024 г. 1:11
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey115 ноября 2024 г. 17:04
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProject4 июня 2022 г. 13:49
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9Anonim25 октября 2024 г. 19:10
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Следите за нами в социальных сетях