Template engine что за папка

Это просто: щелкните на рабочий стол правой кнопкой мыши. В появившемся меню выберите «Новое-> Приложение». Введите заголовок программы, и она появится на рабочем столе.

Это делается в две стадии:

Убедитесь, что у вас есть доступ к монтированию/размонтированию этого устройства

Например, для монтирования дискеты, ваш /etc/fstab должен включать

Создайте файл kdelnk для этой файловой системы

Например, для устройства kdelnk-файл должен быть:

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

Однако, при использовании хранителя экрана в качестве фона, вы тратите некоторое количество ресурсов процессора и X.

Поддержка мыши с колесом прокрутки будет добавлена в Qt 2.0. Ну а пока, для использования колеса в KFM, KEdit и не-KDE приложений, как Emacs, попробуйте взять IMWheel на http://solaris1.mysolution.com/

Папка Templates содержит элементы, которые вы можете легко создать где угодно (на Рабочем столе или в окне файл-менеджера) выбором пункта меню Новое в контекстовом меню (щелчок правой кнопкой мыши) там, где вы хотите разместить этот элемент.

Либо, напишите скрипт оболочки (shell). Если вы используете KDE 1.0, скрипт должен выглядеть примерно так:

Если вы используете KDE 1.1, тогда вам не нужно использовать скрипты оболочки. Вы просто должны выполнить следующее:

Возьмите MacOS и другие темы с http://kde.themes.org. Вы можете найти другие дополнительные пиктограммы на http://icons.themes.org/.

Многие пользователи используют по умолчанию шрифты в разрешением 75 dpi (точек на дюйм). Если вы установили шрифты с разрешением 100 точек на дюйм, убедитесь, что ваш файл XF86Config содержит эти шрифты в пути ДО шрифтов с разрешением 75 dpi. Вот пошаговая процедура как это сделать:

Источник

Первые шаги в aiohttp

Введение

Школа состояла из 6 лекций, шаг за шагом погружавших студентов в мир веб-разработки. На них были рассмотрены такие темы как сетевые протоколы, взаимодействие backend-а и frontend-а, компоненты веб-сервера и многое другое. Лейтмотивом курса было изучение асинхронного веб-программирования на Python, в частности изучение фреймворка aiohttp.

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

Студенты задавали достаточно разные по уровню понимания вопросы, начиная от “Как создать отложенную задачу, используя только asyncio?” и заканчивая “Почему нельзя использовать Django для асинхронного программирования?” (имелась в виду полностью синхронная версия Django). В коде наши менторы тоже находили ошибки, связанные с недостаточным пониманием предмета, например, использование синхронного драйвера для базы данных в асинхронном проекте.

По результатам курса, я решил написать небольшой туториал, рассказывающий о создании базового aiohttp-сервиса с нуля и затрагивающий самые сложные для студентов вопросы: как сделать асинхронное python-приложение, как работать с базой данных и как разложить свой проект в интернете.

В цикле статей мы рассмотрим следующие темы:

Асинхронная работа с базой данных и автоматические миграции

Работа с HTML-шаблонами с помощью Jinja2

Размещение нашего приложения в Интернете с помощью сервиса Heroku

А также сигналы, обработку ошибок, работу с Docker’ом и многое другое.

Эта статья – первая из трех, и ее цель – помочь начинающим aiohttp-программистам написать первое “hello-world” приложение.

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

Мы пройдем по шагам:

Создание проекта

Все команды в статье были выполнены в операционной системе OSX, но также должны работать в любой *NIX системе, например в Linux Ubuntu. Во время разработки я буду использовать Python 3.7.

Давайте создадим папку aiohttp_server, которая в дальнейшем будет называться корнем проекта. В ней создадим текстовый файл requirements.txt, который будет содержать все необходимые для работы приложения зависимости и их версии. Запишем в него следующие модули:

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

После этого в начале строки терминала должна появится надпись (venv) — это означает что виртуальное окружение успешно активировано. Установим необходимые модули:

Структура проекта

Создадим в папке aiohttp_server следующую структуру:

Теперь откроем файл main.py и добавим в него следующее:

После предварительной настройки можно создать первый View.

Первый View

View — это некий вызываемый объект, который принимает на вход HTTP-запрос — Request и возвращает на пришедший запрос HTTP-ответ — Response.

Http-запрос содержит полезную информацию, например url запроса и его контекст, переданные пользователем данные и многое другое. В контексте запроса содержатся данные, которые мы или aiohttp добавили к этому запросу. Например, мы предварительно авторизовали пользователя — чтобы повторно не проверять авторизацию пользователя из базы во всех View и не дублировать код, мы можем добавить объект пользователя в контекст запроса. Тогда мы сможем получить нашего пользователя во View, например, так: request[‘user’].

В файле views.py в папке app/forum напишем следующий код:

Здесь создается функциональный View (function-based View). Определение “функциональный” означает, что код оформлен в виде функции, а не классом (в следующей части мы коснемся и class-based View).

Рассмотрим написанную функцию детальнее: функция обернута в декоратор @aiohttp_jinja2.template(«index.html») — этот декоратор передает возвращенное функцией значение в шаблонизатор Jinja2, а затем возвращает сгенерированную шаблонизатором html-страницу как http-ответ. В данном случае возвращенным значением будет словарь, значения которого подставляются в html-файл index.html.

Читайте также:  какие символы недопустимы в имени переменных

Отдельно стоит заметить, что объект запроса request передается как аргумент функции index. Мы не используем request в этой функции, но будем использовать в дальнейшем.

HTTP-запрос отправляется на конкретный url-адрес. Для передачи HTTP-запроса в нужный View необходимо задать эту связь в приложении с помощью Route.

Первый Route

Route — это звено, связывающее адрес, по которому был отправлен запрос и код View, в котором этот запрос будет обработан. То есть, если пользователь перейдет в корень нашего сайта (по адресу /), то объект запроса будет передан в View index и оттуда же будет возвращен ответ. Подробней про Route можно прочитать тут.

В файл routes.py необходимо добавить следующий код:

Первый Template

Теперь нам осталось только добавить в templates/index.html код верстку нашей страницы. Его можно найти по этой ссылке.

Template — это html-шаблон, в который подставляются данные, полученные в результате обработки запроса. В примере в коде View отдается словарь с ключом title, шаблонизатор Jinja2 ищет в указанном html-шаблоне строки <></em> и заменяет их на значение из словаря по данному ключу. Это простейший пример, шаблоны позволяют делать намного больше: выполнять операции ветвления, циклы и другие операции, например, суммирование. Примеры использования можно посмотреть в документации jinja2.</p> <h2>Запуск приложения</h2> <p>Мы создали первую версию нашего приложения! Осталось запустить его следующей командой в терминале (убедитесь, что находитесь в папке <em>aiohttp_server</em>):</p> <p>Вы должны увидеть следующий текст в консоли. Он означает, что сервер запущен на порту 8080.</p> <p>Давайте теперь посмотрим результаты нашей работы! Для этого перейдите по адресу http://0.0.0.0:8080 в браузере. Вы должны увидеть первую версию нашего приложения. При клике на кнопку “Отправить” должно возникнуть сообщение о том, что отзыв отправлен.</p> <p style="clear: both"> <img decoding="async" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%200%200'%3E%3C/svg%3E" data-lazy-src="https://habr.com/img/image-loader.svg"/><noscript><img decoding="async" src="https://habr.com/img/image-loader.svg"/></noscript></p> <p>Поздравляю! Вы успешно создали первое приложение на aiohttp!</p> <h2>Заключение</h2> <p>В статье рассмотрено создание простого приложения на aiohttp, которое принимает запрос пользователя и отдает html-страницу. Мы затронули:</p> <p>Настройку виртуального окружения</p> <p>Базовую настройку проекта на aiohttp</p> <p>Весь код статьи можно найти на гитхабе.</p> <p>Пользуясь случаем, приглашаю всех читателей, интересующихся веб-разработкой, к нам на бесплатные занятия школу KTS. А для более опытных читателей сейчас идет запись на продвинутые курсы для backend-разработчиков, желающих повысить свои навыки в асинхронной веб-разработке. Всю информацию о всех школах можно найти на сайте, а также в нашем телеграм-чате.</p> <p><noindex><a target="_blank" rel="nofollow" href="https://comp.autowestnik.ru/goto/http://habr.com/ru/company/kts/blog/560058/" >Источник</a></noindex></p> <h2>Файлы шаблона</h2> <p>Как говорилось в разделе Основы, в минимальный набор файлов шаблона должны входить два файла: собственно шаблон <i>.tpl</i> и дескриптор шаблона <i>.tdd</i>. Остальные файлы предназначены для расширения функциональных возможностей шаблона.</p> <h3>Файл для описания шаблонов сайта</h3> <h3>Куда помещать произвольные пользовательские файлы?</h3> <p>В принципе, файлы изображений можно поместить в следующие папки: templates, datafiles, xfiles или в любые другие созданные вами папки, в том числе, вложенные в папки, названные выше. Однако, лучше придерживаться описанных ниже правил по размещению файлов изображений, медиа-файлов, да и вообще любых произвольных файлов. </p> <ul> </ul> <h4>Папка templates</h4> <p>Не помещайте в папку templates файлы, относящиеся к контенту и файлы, предназначенные только для данного сайта, например, логотип сайта. Если вы решите скопировать всю папку templates для другого сайта, то вам придется заменять все такие файлы. Это, в обшем, не проблема, так как файлы придется заменять в любом случае, даже если они находятся в другой папке. Дело в другом — папкой temlates могут пользоваться другие сайты, о чем читайте ниже.</p> <p>В папке templates (в также в ее подпапках) рекомендуется держать картинки, относящиеся только к общему дизайну сайта (фоны, элементы оформления).</p> <h4>datafiles — папка системных файловых данных</h4> <h4>xfiles — папка произвольных файловых данных</h4> <p>Все файлы, загружаемые в ручном режиме и касающиеся только данного сайта, рекомендуется помещать именно сюда.</p> <p>Естественно, загружать файлы можно с помощью FTP-клиента. Для упорядочивания данных, можно создавать подпапки.</p> <p>Система никак не контролирует эти файлы, за исключением закачки файлов через текстовый редактор. При закачке файлов через текстовый редактор (как картинок), файлы попадают в корень папки xfiles. При этом производится переименовывание в латиницу, а при наличии в папке файла с таким же именем, производится приписывание к имени нового файла численного окончания.</p> <h3>Одна папка templates на нескольких сайтов</h3> <p>Несколько сайтов могут работать на одном комплекте шаблонов. Обычно такая ситуация возникает, когда делаются копии одного и того же сайта для разных городов.</p> <p><b>Чтобы использовать шаблоны другого сайта необходимо:</b> </p> <p>На сайте-акцепторе во всех путях вида templates/. нужно заменить слово <i>templates</i> на методы Blox::info(‘templates’,’url’) или Blox::info(‘templates’,’dir’). Первый нужно использовать при создании URL, второй при указаниии абсолютных путей к файлам в файловой системе. Пример:</p> <p>Когда вы делаете копию сайта, вы помимо всего прочего будете копировать и базу данных исходного сайта. Перед загрузкой базы данных на новый сайт, не поленитесь проверить ее на наличие строки «templates/», и замените его на соответствующий абсолютный URL сайта-донора. </ol> </p> <p><noindex><a target="_blank" rel="nofollow" href="https://comp.autowestnik.ru/goto/http://bloxcms.net/documentation/template-files.htm" >Источник</a></noindex></p> <h2>Найден секретный способ освободить до 20 Гб памяти в телефоне</h2> <p>Существует несколько способов очистить систему Android от мусора и освободить таким образом память устройства. Это могут быть как встроенные сервисы, так и некоторые сторонние приложения для очистки. Но что делать, если ни один способ вам не помог и телефон все равно сигнализирует о нехватке памяти? В этом случае можно прибегнуть к ручной очистке и освободить таким образом до 20 Гб памяти смартфона.</p> <h2><strong>Удаление папки Telegram</strong></h2> <p>В 2021 году этот кроссплатформенный мессенджер по праву стал самым популярным приложением в мире, обогнав по числу скачиваний даже такого гиганта как Tik-Tok.</p> <p>Но у Telegram есть одна небольшая проблема – вся просмотренная вами информация сохраняется во внутренней памяти телефона, тем самым засоряя систему.</p> <p>Если вы являетесь активным пользователем Telegram, рекомендуем периодически очищать содержимое папки с приложением. Для этого достаточно перейти в любой файловый менеджер и полностью удалить папку Telegram. Не стоит переживать, с приложением после удаления ничего не случится. Система при следующем входе автоматически создаст папку Telegram заново.</p> <p>Многим пользователям, которые делают такую процедуру впервые после установки Telegram, удается очистить таким образом от 1 до 10 Гб памяти. Проверьте и убедитесь сами.</p> <h2><strong>Удаление папки.Thumbnails</strong></h2> <p>Следующий способ – удаление папки, которая содержится в корневом разделе DCIM (или Pictures) системы Android и содержит в себе все мини копии картинок и фотографий, которые встречаются вам при серфинге в интернете и в приложениях. Этот раздел также может занимать очень большой объем данных, если ранее вы еще не проводили подобную очистку.</p> <p>Папка.Thumbnails довольно хитрая и скрыта от глаз пользователя в каталогах системы. Чтобы ее найти и удалить, необходимо сначала включить отображение скрытых папок в настройках файлового менеджера.</p> <p>В некоторых случаях системный файловый менеджер также не дает увидеть эту папку. В этом случае можно попробовать установить стороннее приложение, например ES-проводник, а затем перейти в каталог DCIM (Pictures), включить отображение скрытых папок и удалить папку.Thumbnails.</p> <p>Если вы больше не хотите, чтобы миниатюры засоряли вам память устройства, можно немного перехитрить систему, создав в папке DCIM новый файл с другим расширением, но с тем же названием.Thumbnails.</p> <p>Система Android устроена таким образом, что никогда не позволит создать два файла с одинаковым названием, поэтому папка.Thumbnails больше не сможет там появиться. Сделать это также можно с помощью ES-проводника.</p> <p>Нажимаем на три точки в верхнем правом углу приложения → «+Создать» → Файл. Называем файл.Thumbnails (обязательно ставим точку вначале).</p> <p>Готово! Теперь наш созданный файл не позволит системе Android создать папку.Thumbnails, а значит система больше не будет засоряться лишними миниатюрами.</p> <h2><strong>Удаление папки Data</strong></h2> <p>Еще одна папка, занимающая большое количество памяти в телефоне – папка Data, которая находится внутри каталога Android. Эта папка содержит кэш, а также некоторые настройки и служебную информацию о приложениях. Но каких-либо серьезных системных данных, влияющих на работу системы в целом, она не содержит. Поэтому ее также можно удалить, освободив до 10 Гб памяти.</p> <p>Удалять ее нужно только в обход корзины, так как сама корзина является вложенной в папку Data, о чем система предупреждает при попытке удалить ее стандартным путем. Поэтому нам потребуется снова воспользоваться сторонним файловым менеджером, который позволит удалить папку Data напрямую, без промежуточных инстанций.</p> <p>Открываем ES проводник и переходим во внутренний каталог системы. Затем переходим в папку Android→Выделяем папку Data→ Нажимаем Удалить. Убираем галочку с пункта «Перенести в корзину» и нажимаем ОК. Нам удалось очистить таким образом почти 3 Гб внутренней памяти.</p> <h2><strong>Заключение</strong></h2> <p>В далеком 1981 году на пути становления IBM, Билл Гейтс произнес, ставшую сегодня забавным мемом, фразу: «В будущем 640 Кб будет достаточно для каждого». Из-за особенностей первых процессоров, никто не мог и представить, что когда-нибудь в компьютерах, а тем более в мобильных устройствах удастся разместить большее количество памяти, а главное, что кому-то может понадобиться такой объем информации.</p> <p>Несмотря на то, что сегодня любой смартфон обладает памятью в десятки тысяч раз, превышающий этот объем, нехватка памяти до сих пор остается актуальной проблемой, особенно для бюджетных моделей смартфонов. Мы надеемся, что с помощью нашей инструкции вам удастся очистить ваше устройство и наконец решить данную проблему.</p> <p><noindex><a target="_blank" rel="nofollow" href="https://comp.autowestnik.ru/goto/http://hi-tech.mail.ru/news/53483-sekretnyy-sposob-osvobodit-do-20-gb-pamyati-v-telefone/" >Источник</a></noindex></p> <h2>Django tips & tricks</h2> <p style="clear: both"><img decoding="async" style="float: left; margin: 0 10px 5px 0;" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%200%200'%3E%3C/svg%3E" data-lazy-src="https://habr.com/img/image-loader.svg"/><noscript><img decoding="async" style="float: left; margin: 0 10px 5px 0;" src="https://habr.com/img/image-loader.svg"/></noscript>Приветствую!</p> <p>В этом посте — небольшие советы по работе с Django, которые могут пригодиться начинающим разработчикам. Как я хотел бы знать это в начале моего пути освоения Django. <br/>Рассматривать эти советы следует с долей критицизма. Буду рад, если вы найдёте неточности / лучшее решение, или предложите свои «фишки» для django, которых нет в документации.</p> <p>Итак, начнём издалека, а уж потом перейдём к деталям.</p> <p style="clear: both"><img decoding="async" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%200%200'%3E%3C/svg%3E" data-lazy-src="https://habr.com/img/image-loader.svg"/><noscript><img decoding="async" src="https://habr.com/img/image-loader.svg"/></noscript> </p> <h4>Виртуальное окружение</h4> <p>Если вы не используете virtualenv для вашего django-приложения — то обязательно попробуйте.</p> <p>Видимость / невидимость глобальных программ из virtualenv устанавливается отсутствуем / наличием файла [virtualenv]/lib/python*.*/no-global-site-packages.txt. Вот так просто.</p> <p>Кстати, рекомендую всем статью про «изолированность» virtualenv: Why I hate virtualenv and pip (сайт тормозит, смог открыть только через web.archive.org). В ней рассматривается, насколько virtualenv действительно изолирован от «внешней» среды — если кратко, то это лишь частичная изоляция.</p> <p style="clear: both"><img decoding="async" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%200%200'%3E%3C/svg%3E" data-lazy-src="https://habr.com/img/image-loader.svg"/><noscript><img decoding="async" src="https://habr.com/img/image-loader.svg"/></noscript> </p> <h4>ipython</h4> <h4>Структура проекта</h4> <p>Django по умолчанию при создании проекта или приложения создаёт необходимые каталоги. Но и самим нужно думать.</p> <h5>Как проект назовёшь, так и будешь импортировать</h5> <p>Называйте ваш проект project (django-admin.py startproject project) — ну или другим, но одинаковым именем для всех проектов. Раньше я называл проекты соответственно домену, но при повторном использовании приложений в других проектах приходилось менять пути импорта — то from supersite import utils, то from newsite import utils. Это путает и отвлекает. Если расширить этот совет — зафиксируйте (унифицируйте) для себя структуру каталогов всех ваших проектов и строго её придерживайтесь.</p> <h5>Куда сохранять html-шаблоны</h5> <p>Никогда, <b>никогда</b> не кидайте шаблоны (.html) в папку templates вашего приложения. Всегда создавайте дополнительный каталог с названием, совпадающим с именем приложения. <br/>Вот это плохо, т.к. создаёт коллизию шаблонов, например, при <% include 'main.html' %>:</p> <p>К слову, если вы используете <% include 'some_template.html' %>, то велика вероятность, что что-то не так. Почему? <br/>Пример:</p> <p>1) KISS едет лесом. С одной стороны, код страницы разбит на несколько — master.html и подключаемый slave.html, и это удобно для разделения больших html-страниц на части. Но в данном случае переменная var передаётся в шаблон slave.html неявно — var передатся в master.html, а slave.html просто «цепляет» контекст master’а. Таким образом, мы видим, что шаблон внутри <% include %>зависит от контекста основного шаблона. Мы вынуждены следить за контекстом родительского шаблона, иначе в дочерний может попасть что-нибудь не то. <br/>2) По моим наблюдениям, <% include %>дорогой в плане рендеринга. Лучше его избегать.</p> <p>Что делать? Если очень хочется одни шаблоны включать в другие — используйте inclusion tags (о них читать ниже). Но проще — просто пишите всё в одном файле:</p> <h5>settings.py</h5> <p>В settings.py пишем в начале:</p> <h5>Корень проекта</h5> <p>Задайте корень проекта в settings.py — это облегчит жизнь потом:</p> <h4>Контекстные процессоры (context_processors.py), <% include %>и inclusion tags</h4> <p>Используйте контекстные процессоры только если вам нужно добавить переменные в контекст <b>каждой страницы сайта</b> — ведь контекстные процессоры будут вызываться для любой страницы, даже если вы не воспользуйтесь их результатами. Лично я использую их для передачи номера телефона в контекст шаблона — этот номер реально на каждой странице выводится, и не единожды. Ещё пример — меню сайта. Я прописал заголовки и ссылки в контекстном процессоре, и если мне нужно будет добавить новый раздел в меню — я просто добавлю его в контекстный процессор, и он автоматически добавится везде на сайте.</p> <p>Есть одна ошибка — использование контекстных процессоров для виджетов. Например, у вас на сайте есть колонка новостей, которая выводится всегда, т.е. на каждой страничке. Казалось бы, создать news/context_processors.py, и в контекст добавлять переменную news с новостями, а в шаблоне <% include 'news/news_widget.html' %>, или даже <% load news_widget %><% news_widget news %>…</p> <p>Это работает, но это замусоривает контекст и, кроме того, кто знает, всегда ли у вас будет эта колонка. Выход есть — используйте inclusion tag. Вы просто пишете в шаблоне <% news %>, а уже этот templatetag ищет новости и вставляет колонку новостей. И работает он только тогда, когда вы его реально запускаете — т.е. пишете <% news %>в шаблоне.</p> <p style="clear: both"><img decoding="async" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%200%200'%3E%3C/svg%3E" data-lazy-src="https://habrastorage.org/r/w780q1/getpro/habr/post_images/871/644/51e/87164451efd98e7a5c0e7d183f28ef55.jpg"/><noscript><img decoding="async" src="https://habrastorage.org/r/w780q1/getpro/habr/post_images/871/644/51e/87164451efd98e7a5c0e7d183f28ef55.jpg"/></noscript> </p> <h4>Батарейки</h4> <h5>django-debug-toolbar-template-timings</h5> <p>Все его знают и, наверно, используют. Но есть django-debug-toolbar-template-timings — плагин к debug toolbar, который замеряет время рендеринга шаблонов. А учитывая, что шаблоны django довольно «дорогие» (рендерятся долго), то для ускорения сайта этот плагин — то что доктор прописал.</p> <h5>adv_cache_tag</h5> <p>django-adv-cache-tag позволяет очень гибко управлять кешированием в шаблонах — версионность, сжатие, частичное кэширование. Просто оцените:</p> <h5>django-mail-templated</h5> <p>Шаблоны email писем — это то, чего не хватает django. django-mail-templated</p> <h5>django-ipware</h5> <h5>Beautiful Soup</h5> <p>Не пишите свой парсер html. Не парсите html сами. Всё уже есть.</p> <h4>Templatetags, которые могут пригодиться</h4> <h5>add_class</h5> <p>Если вы создаёте форму и хотите для каждого input-а задать стиль, класс или placeholder, то django заставит вас нарушить принципы и прописать все стили прямо в forms.py:</p> <p>Данный фильтр добавляет класс к тегам, но можно переписать и добавлять любое свойство. </p> <h5>is_current_page</h5> <p>Иногда нужно что-то выводить в шаблоне, если открыта определённая страница. Например, подсветить кнопку «магазин» в меню, если пользователь сейчас в разделе магазина. Предлагаю следующий вариант:</p> <p>Это фильтр, а не тэг, и причина тут одна: можно строить совершенно дичайшие конструкции с <% if %>. Например, если текущая страница — карточка товара, и при этом пользователь авторизован:</p> <p>Есть и альтернативная, более точная, реализация, в которой используются аргументы (args или kwargs) для определения точной страницы (т.е. не просто «страница какого-либо товара», а «страница товара с ></p> <p style="clear: both"><img decoding="async" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%200%200'%3E%3C/svg%3E" data-lazy-src="https://habrastorage.org/r/w780q1/getpro/habr/post_images/bc6/a59/13d/bc6a5913dd401f48a545de54669c812e.jpg"/><noscript><img decoding="async" src="https://habrastorage.org/r/w780q1/getpro/habr/post_images/bc6/a59/13d/bc6a5913dd401f48a545de54669c812e.jpg"/></noscript> </p> <h4>Модели</h4> <h5>Пустые</h5> <p>Модели могут быть пустыми. Вот так:</p> <p>В данном случае Phrase является связующим звеном между PhraseEn и PhraseRu, хотя сама в себе ничего не содержит. Полезно, когда две модели равнозначны, и их необходимо связать в единое целое.</p> <h5>Generic relation mixin</h5> <p>Объекты GenericRelation всегда возвращаются QuerySet’ом, даже есть мы точно знаем, что объект один:</p> <p>Если нужно получить доступ к токену, мы пишем registration.tokens.first(). Но мы-то знаем, что токен один, и хотим писать просто registration.token и получить сразу заветный токен. Это возможно при помощи mixin:</p> <p>Теперь registration.token работает!</p> <h5>get_absolute_url</h5> <p>Старайтесь не писать <% url 'shop/product' %>. <br/>Лучше для каждой модели задайте метод get_absolute_url(), и используйте << object.get_absolute_url >>. Заодно и ссылка «смотреть на сайте» появится в админке.</p> <h5>pre_save</h5> <p>В pre_save можно узнать, изменится ли модель после сохранения или нет. Цена — запрос к БД для получения старой записи из базы.</p> <h4>Формы</h4> <p>Этот паттерн уже был на хабре, но он слишком хорош, чтобы не упомянуть его.</p> <p>На этом всё. Спасибо за внимание.</p> <p><b>UPD.</b> Как обычно на Хабре, в комментариях хабражители высказали свои мнения и предложили кучу замечательных идей, дополнений и замечаний к статье. Я не стал их вносить в статью, но вместо этого настоятельно рекомендую ознакомиться с комментариями к статье.</p> <p><noindex><a target="_blank" rel="nofollow" href="https://comp.autowestnik.ru/goto/http://habr.com/ru/post/224011/" >Источник</a></noindex></p> </div> </article> <meta itemprop="author" content="admin"> <meta itemscope itemprop="mainEntityOfPage" itemType="https://schema.org/WebPage" itemid="https://comp.autowestnik.ru/remont/8033.html" content=""> <meta itemprop="dateModified" content="2022-06-02"> <meta itemprop="datePublished" content="2022-06-02T17:39:40+00:00"> <div itemprop="publisher" itemscope itemtype="https://schema.org/Organization" style="display: none;"><div itemprop="logo" itemscope itemtype="https://schema.org/ImageObject"><img itemprop="url image" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%200%200'%3E%3C/svg%3E" alt="Информ портал о технике и не только" data-lazy-src="https://comp.autowestnik.ru/wp-content/uploads/2026/04/free-icon-marketing-automation-17532434.png"><noscript><img itemprop="url image" src="https://comp.autowestnik.ru/wp-content/uploads/2026/04/free-icon-marketing-automation-17532434.png" alt="Информ портал о технике и не только"></noscript></div><meta itemprop="name" content="Информ портал о технике и не только"><meta itemprop="telephone" content="Информ портал о технике и не только"><meta itemprop="address" content="https://comp.autowestnik.ru"></div> </main> </div> <aside id="secondary" class="widget-area" itemscope itemtype="http://schema.org/WPSideBar"> <div class="sticky-sidebar js-sticky-sidebar"> <div id="categories-3" class="widget widget_categories"><div class="widget-header">Рубрики</div> <ul> <li class="cat-item cat-item-3"><a href="https://comp.autowestnik.ru/remont">ремонт авто и техники</a> </li> </ul> </div> <div id="recent-posts-3" class="widget widget_recent_entries"> <div class="widget-header">Свежие записи</div> <ul> <li> <a href="https://comp.autowestnik.ru/remont/administrativnyy-shtraf-300-rubley-za-chto-mozhet-byt.html">Административный штраф 300 рублей за что может быть</a> </li> <li> <a href="https://comp.autowestnik.ru/remont/luchshe-gorkaya-no-pravda-chem-krasivaya-no-lozh-filatov.html">лучше горькая но правда чем красивая но ложь филатов</a> </li> <li> <a href="https://comp.autowestnik.ru/remont/luchshe-goret-chem-tlet.html">лучше гореть чем тлеть</a> </li> <li> <a href="https://comp.autowestnik.ru/remont/luchshe-golub-v-rukah-chem-zhuravl-v-nebe.html">лучше голубь в руках чем журавль в небе</a> </li> <li> <a href="https://comp.autowestnik.ru/remont/luchshe-golodat-chem-est-chto-popalo-tsitata.html">лучше голодать чем есть что попало цитата</a> </li> </ul> </div><div id="custom_html-9" class="widget_text widget widget_custom_html"><div class="textwidget custom-html-widget"><div id="Q_sidebar"></div></div></div> </div> </aside> <div id="related-posts" class="related-posts fixed"><div class="related-posts__header">Вам также может понравиться</div><div class="post-cards post-cards--vertical"> <div class="post-card post-card--related post-card--thumbnail-no"> <div class="post-card__title"><a href="https://comp.autowestnik.ru/remont/administrativnyy-shtraf-300-rubley-za-chto-mozhet-byt.html">Административный штраф 300 рублей за что может быть</a></div><div class="post-card__description">Нарушения КоАП и размеры штрафов Такие нарушения определены</div> </div> <div class="post-card post-card--related post-card--thumbnail-no"> <div class="post-card__title"><a href="https://comp.autowestnik.ru/remont/luchshe-gorkaya-no-pravda-chem-krasivaya-no-lozh-filatov.html">лучше горькая но правда чем красивая но ложь филатов</a></div><div class="post-card__description">10 цитат из пьесы Леонида Филатова «Про Федота-стрельца</div> </div> <div class="post-card post-card--related post-card--thumbnail-no"> <div class="post-card__title"><a href="https://comp.autowestnik.ru/remont/luchshe-goret-chem-tlet.html">лучше гореть чем тлеть</a></div><div class="post-card__description">«Лучше сгореть быстро, чем долго тлеть» Как бывший</div> </div> <div class="post-card post-card--related post-card--thumbnail-no"> <div class="post-card__title"><a href="https://comp.autowestnik.ru/remont/luchshe-golub-v-rukah-chem-zhuravl-v-nebe.html">лучше голубь в руках чем журавль в небе</a></div><div class="post-card__description">Смысл пословицы «Лучше синица в руках, чем журавль</div> </div> </div></div> </div> </div> <div class="site-footer-container "> <div class="footer-navigation fixed" itemscope itemtype="http://schema.org/SiteNavigationElement"> <div class="main-navigation-inner full"> <div class="menu-tehnicheskoe-menyu-container"><ul id="footer_menu" class="menu"><li id="menu-item-207521" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-207521"><a href="https://comp.autowestnik.ru/politika-konfidentsialnosti.html">Политика конфиденциальности</a></li> <li id="menu-item-207522" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-207522"><a href="https://comp.autowestnik.ru/pravoobladatelyam.html">Правообладателям</a></li> <li id="menu-item-207523" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-207523"><a href="https://comp.autowestnik.ru/kontakty.html">Контакты</a></li> </ul></div> </div> </div> <footer id="colophon" class="site-footer site-footer--style-gray full"> <div class="site-footer-inner fixed"> <div class="footer-bottom"> <div class="footer-info"> © 2026 Внимание! Информация, опубликованная на сайте, носит исключительно ознакомительный характер и не является рекомендацией к применению. </div> <div class="footer-counters"> <script type="text/javascript"> (function(m,e,t,r,i,k,a){ m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; m[i].l=1*new Date(); for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }} k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a) })(window, document,'script','https://mc.yandex.ru/metrika/tag.js?id=108687020', 'ym'); ym(108687020, 'init', {ssr:true, clickmap:true, referrer: document.referrer, url: location.href, accurateTrackBounce:true, trackLinks:true}); </script> <noscript><div><img src="https://mc.yandex.ru/watch/108687020" style="position:absolute; left:-9999px;" alt=""/></div></noscript> </div></div> </div> </footer> </div> <button type="button" class="scrolltop js-scrolltop" data-mob="on"></button> </div> <script type="speculationrules"> {"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/wp-content/uploads/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/reboot/*","/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]} </script> <script>var pseudo_links = document.querySelectorAll(".pseudo-clearfy-link");for (var i=0;i<pseudo_links.length;i++ ) { pseudo_links[i].addEventListener("click", function(e){ window.open( e.target.getAttribute("data-uri") ); }); }</script><script>document.addEventListener("copy", (event) => {var pagelink = "\nИсточник: https://comp.autowestnik.ru/remont/8033.html";event.clipboardData.setData("text", document.getSelection() + pagelink);event.preventDefault();});</script><script type="text/javascript" id="reboot-scripts-js-extra"> /* <![CDATA[ */ var settings_array = {"rating_text_average":"\u0441\u0440\u0435\u0434\u043d\u0435\u0435","rating_text_from":"\u0438\u0437","lightbox_display":"","sidebar_fixed":"1"}; var wps_ajax = {"url":"https://comp.autowestnik.ru/wp-admin/admin-ajax.php","nonce":"f7595f7970"}; //# sourceURL=reboot-scripts-js-extra /* ]]> */ </script> <script type="text/javascript" src="https://comp.autowestnik.ru/wp-content/themes/reboot/assets/js/scripts.min.js" id="reboot-scripts-js"></script> <script>!function(){var t=!1;try{var e=Object.defineProperty({},"passive",{get:function(){t=!0}});window.addEventListener("test",null,e)}catch(t){}return t}()||function(i){var o=!0,s=!1;EventTarget.prototype.addEventListener=function(t,e,n){var r="object"==typeof n,a=r?n.capture:n;n=r?n:{},"touchstart"!=t&&"scroll"!=t&&"wheel"!=t||(n.passive=void 0!==n.passive?n.passive:o),n.capture=void 0!==a?a:s,i.call(this,t,e,n)}}(EventTarget.prototype.addEventListener);</script><script> window.lazyLoadCallbackByFlat=function(r){var t,a;120<r.naturalWidth||(t="maxresdefault",(a=new Image).src=r.src.replace(t,"hqdefault"),a.onload=function(){var a;120<this.naturalWidth?r.src=this.src:((a=new Image).src=r.src.replace(t,"sddefault"),a.onload=function(){var a;120<this.naturalWidth?r.src=this.src:((a=new Image).src=r.src.replace(t,"mqdefault"),a.onload=function(){var a;120<this.naturalWidth?r.src=this.src:((a=new Image).src=r.src.replace(t,"default"),a.onload=function(){120<this.naturalWidth&&(r.src=this.src)})})})})}; window.lazyLoadOptions = { elements_selector: "img[data-lazy-src],.rocket-lazyload,iframe[data-lazy-src]", data_src: "lazy-src", data_srcset: "lazy-srcset", data_sizes: "lazy-sizes", class_loading: "lazyloading", class_loaded: "lazyloaded", threshold: 300, callback_loaded: function(element) { if ( element.tagName === "IFRAME" && element.dataset.rocketLazyload == "fitvidscompatible" ) { if (element.classList.contains("lazyloaded") ) { if (typeof window.jQuery != "undefined") { if (jQuery.fn.fitVids) { jQuery(element).parent().fitVids(); } } } } }}; window.addEventListener('LazyLoad::Initialized', function (e) { var lazyLoadInstance = e.detail.instance; if (window.MutationObserver) { var observer = new MutationObserver(function(mutations) { var image_count = 0; var iframe_count = 0; var rocketlazy_count = 0; mutations.forEach(function(mutation) { for (i = 0; i < mutation.addedNodes.length; i++) { if (typeof mutation.addedNodes[i].getElementsByTagName !== 'function') { return; } if (typeof mutation.addedNodes[i].getElementsByClassName !== 'function') { return; } images = mutation.addedNodes[i].getElementsByTagName('img'); is_image = mutation.addedNodes[i].tagName == "IMG"; iframes = mutation.addedNodes[i].getElementsByTagName('iframe'); is_iframe = mutation.addedNodes[i].tagName == "IFRAME"; rocket_lazy = mutation.addedNodes[i].getElementsByClassName('rocket-lazyload'); image_count += images.length; iframe_count += iframes.length; rocketlazy_count += rocket_lazy.length; if(is_image){ image_count += 1; } if(is_iframe){ iframe_count += 1; } } } ); if(image_count > 0 || iframe_count > 0 || rocketlazy_count > 0){ lazyLoadInstance.update(); } } ); var b = document.getElementsByTagName("body")[0]; var config = { childList: true, subtree: true }; observer.observe(b, config); } }, false);</script><script data-no-minify="1" async src="https://comp.autowestnik.ru/wp-content/plugins/rocket-lazy-load/assets/js/16.1/lazyload.min.js"></script><script>function lazyLoadThumb(e){var t='<img loading="lazy" onload="lazyLoadCallbackByFlat(this);" data-lazy-src="https://i.ytimg.com/vi/ID/maxresdefault.jpg" alt="" width="1280" height="720">',a='<div class="play"></div>';return t.replace("ID",e)+a}function lazyLoadYoutubeIframe(){var e=document.createElement("iframe"),t="ID?autoplay=1";t+=0===this.dataset.query.length?'':'&'+this.dataset.query;e.setAttribute("src",t.replace("ID",this.dataset.src)),e.setAttribute("frameborder","0"),e.setAttribute("allowfullscreen","1"),e.setAttribute("allow", "accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"),this.parentNode.replaceChild(e,this)}document.addEventListener("DOMContentLoaded",function(){var e,t,a=document.getElementsByClassName("rll-youtube-player");for(t=0;t<a.length;t++)e=document.createElement("div"),e.setAttribute("data-id",a[t].dataset.id),e.setAttribute("data-query", a[t].dataset.query),e.setAttribute("data-src", a[t].dataset.src),e.innerHTML=lazyLoadThumb(a[t].dataset.id),e.onclick=lazyLoadYoutubeIframe,a[t].appendChild(e)});</script><script type="text/javascript" src="/otherlocalBD.js"></script> </body> </html>