У меня есть два варианта бокового меню, которые меняются в зависимости от определённого условия следующим образом:
<div class="sidebar">…</div>
<div class="alt-sidebar">…</div>
<script>…
В этом выпуске: советы по недопущению ошибок в коде на React; неофициальные переводы руководств Google по стилю написания кода на JavaScript и TypeScript; 10 полезных приемов для работы с CSS; функции высшего порядка в JavaScript (гайд для новичков).
AbortControllerпредоставляет возможность прерывать веб-запросы в любой момент, не дожидаясь ответа, но этот механизм также можно применить к другим юзкейсам. Подробнее в статье.
Нужна ли регулировка размера текста в CSS-библиотеках для сброса стилей? Разбираем 7 вариантов
Svelte Origins: A JavaScript Documentary. Если у вас все в порядке с английским, этот фильм для вас. Документальный фильм рассказывает историю о том, как появился Svelte, что отличает Svelte и как он меняет игру как JavaScript-фреймворк. В фильме, снятом в разных местах Европы и США, участвуют создатель Svelte Рич Харрис и члены сообщества, которые внесли свой вклад в Svelte и сделали его тем, чем он является сегодня.
Обзор современных возможностей CSS по настройке полосы прокрутки.
Второй выпуск “Аффтарпати” посвящён JavaScript. Гостем стал Тимур Шемсединов – мощный JS-разработчик, гуру Node.js. Темы выпуска: ФП, разработка бэкенда на JS, образование и много чего ещё:
Не судите строго если проблема глупая.
Выучил основы JavaScript и продолжаю путь изучая React. Я почти всегда использую отдельно html и отдельно js файлы. Начав учить React, в туториале всегда js пишется в html файле, и нет инструкций как …
Ловите подборку расширений и плагинов для браузера, облегчающих жизнь программисту: ответы со StackOverflow в виде кода в топе выдаче Google, вызов, обнаружение и тестирование HTTP и REST API, анализатор UX, уменьшение потребления памяти Ch…
подскажите, пожалуйста, каким образом можно реализовать такую первую анимацию отображения страницы – https://ramzes.gg/
Что можно почитать или найти, чтобы реализовать похожее?
Для разработки мобильных приложений требуется, чтобы оно работало на разных операционных системах и чтобы не переписывать код под отдельную операционную систему используют фреймворки.
В этой статье расскажем о двух таких фреймворках: Ionic и React Native.
Что такое кроссплатформенное создание приложений
Кроссплатформенное создание приложений – это способ создать приложение под все мобильные ОС.
Что такое Ionic
Ionic – это стартап Бена Сперри и Макса Линча, которые работали в разных стартапах, а потом основали компанию Drifty development company. Они предложили свое собственное решение – кроссплатформенный инструмент разработки, основанный на веб-технологиях.
Ionic встраивается в HTML, CSS, а последние версии фреймворка позволяют разработчикам использовать любой из фреймворков пользовательского интерфейса JavaScript: Angular, React или Vue.
Marketwatch – приложение для новостей и анализа рынка (AppStore,GooglePlay).
Основатели не афишируют себя.
Скриншот приложения MarketWatch в GooglePlay
Что такое React Native
React Native – это кроссплатформенная платформа разработки, которая позволяет создать приложение максимально приближенное к нативному, используя большую часть кодовой базы для разных платформ: Android и iOS. React Native – это продукт от Facebook*.
Использует JavaScript независимо от платформы.Кроме того, при необходимости вы можете использовать собственные модули в Objective-C, Swift, Java или Kotlin.
Высокая производительность. Код работает на собственном API.
Фреймворк предлагает готовые компоненты пользовательского интерфейса: кнопки, модули, ползунки. Это сокращает время, необходимое для разработки пользовательского интерфейса приложения.
Позволяет вводить новые версии в запущенное приложение без потери текущего состояния.
Бесплатное использование.
Недостатки React Native
Более длительное время разработки. В отличии от Ionic, нужно создавать пользовательскую версию каждого экрана для каждой платформы.
Поскольку время на разработку в React Native больше, могут потребоваться дополнительные инвестиции.
В React Native можно использовать модули, написанные не только на JavaScript. Поэтому требуется поддержка специалистов по другим языкам. И в результате возрастает стоимость разработки. Но этим недостатком можно пренебречь, если использовать один язык программирования.
Размер приложений на React Native больше, чем у приложений на Java или Kotlin.
Примеры приложений на React Native
Instagram**
Знаменитая социальная сеть с фотографиями, историями, личными сообщениями, рекламным кабинетом (AppStore, GooglePlay).
Скриншот приложения Instagram в GooglePlay
*, ** Продукт Meta, деятельность признана экстремистской, запрещена на территории России.
Bloomberg
Медиакомпания, которая поставляет информацию участникам финансового рынка (AppStore, GooglePlay).
На этом этапе мы сделаем и включим в index.html шаблоны resume.html, counters.html, skills.html, interests.html, которые составляют секцию «Резюме» и portfolio.html – для, соответственно, раздела «Портфолио».
Последнее, что мы сделаем на этом этапе – шаблон для секции «Портфолио». Код для шаблона возьмите здесь – portfolio.html. Не забудьте включить портфолио в index.html:
Вся базовая информация о проектах (название и краткое описание) пока что находится прямо в шаблоне portfolio.html. Если добавлять туда еще и подробное описание проектов, объем шаблона быстро станет неприлично большим. Гораздо удобнее иметь отдельный Markdown-файл с подробным описанием каждого проекта: такие карточки проще редактировать и сортировать в нужном порядке.
Для просмотра детальной информации по каждому проекту в портфолио нужно:
добавить в директорию content вложенную папку portfolio;
сохранить в этой папке тестовые карточки проектов;
добавить в mysite.py новый маршрут;
сделать шаблон card.html.
Начнем с mysite.py. Добавьте туда новую переменную:
PORT_DIR = 'portfolio'
Внесите изменения в функцию представления – теперь она должна выглядеть так:
@app.route("/")
def index():
posts = [p for p in flatpages if p.path.startswith(POST_DIR)]
posts.sort(key=lambda item: item['date'], reverse=True)
cards = [p for p in flatpages if p.path.startswith(PORT_DIR)]
cards.sort(key=lambda item: item['title'])
with open('settings.txt', encoding='utf8') as config:
data = config.read()
settings = json.loads(data)
return render_template('index.html', posts=posts, cards=cards, bigheader=True, **settings)
Осталось сделать шаблон для карточек card.html – возьмите код здесь и внесите изменения в шаблон portfolio.html – теперь в нем должен быть такой код. Контент для карточек – здесь.
Раздел портфолио готов
Секция «Блог» и фильтрация по тегам
Как и в секции «Портфолио», в блоге статьи представлены в виде карточек. Загрузка содержимого статьи происходит без обновления страницы, для перехода между записями используется горизонтальный свайп.
Фильтрацию записей в блоге выполняет скрипт isotope.js. Сортировка проводится в соответствии с тегами, которые указываются в YAML-записей. Извлечь теги поможет этот фрагмент кода – его нужно вставить в функцию представления в файле mysite.py:
@app.route("/")
def index():
posts = [p for p in flatpages if p.path.startswith(POST_DIR)]
posts.sort(key=lambda item: item['date'], reverse=True)
cards = [p for p in flatpages if p.path.startswith(PORT_DIR)]
cards.sort(key=lambda item: item['title'])
with open('settings.txt', encoding='utf8') as config:
data = config.read()
settings = json.loads(data)
tags = set()
for p in flatpages:
t = p.meta.get('tag')
if t:
tags.add(t.lower())
return render_template('index.html', posts=posts, cards=cards, bigheader=True, **settings, tags=tags)
Множество tags = set() гарантирует уникальность тегов. Код для самого блога возьмите здесь –blog.html, а тестовые записи –здесь. Добавьте соответствующее включение в index.html:
{% block blog %}
{% include "blog.html" %}
{% endblock %}
Модуль FlatPages передает теги в шаблонизатор, откуда их получает скрипт isotope.js – теперь можно фильтровать контент блога без перезагрузки страницы:
Фильтрация по тегу Django
Но записи по-прежнему рендерятся в тестовом шаблоне post.html и выглядят неказисто. Измените код шаблона на новый и добавьте в папку /static/img/portfolioфоновое изображение. Блоки кода пока что выделены только моноширинным шрифтом. Однако мы установили модуль Pygments, который определяет стили форматирования кода. Все они находятся здесь – .venv\Lib\site-packages\pygments\styles.
Для подсветки синтаксиса добавим в mysite.py маршрут к pigments:
@app.route('/pygments.css')
def pygments_css():
return pygments_style_defs('monokai'), 200, {'Content-Type': 'text/css'}
И добавим ссылку на стиль в шаблон base.html:
<link rel="stylesheet" href="{{ url_for('pygments_css') }}">
Теперь блоки кода выделены:
Подсветка синтаксиса
Контактная форма
Для секции «Контакты» мы создадим отдельный шаблон contacts.html и включим его в index.html:
Наш сайт будет размещаться на хостинге GitHub Pages, который не поддерживает Flask (и вообще поддерживает только Jekyll с ограниченным набором плагинов). Поэтому разместить там можно только статическую копию сайта, которую сгенерирует модуль Frozen Flask. В статическом режиме, естественно, обработка формы работать не будет. Но возможность подключения внешнего обработчика к формам на статических сайтах существует. Мы воспользуемся услугами одного из таких сервисов – Formspree. Полученную после регистрации ссылку нужно вставить в код формы:
Теперь можно получать сообщения от посетителей сайта:
В платной версии есть переадресация после отправки
Посетитель увидит уведомление об отправке, а владелец сайта получит сообщение на емейл, указанный при регистрации. Formspree фильтрует спам. Другие подобные сервисы по обработке форм на статических сайтах –99Inbound иKwesForms.
Страница 404
Осталось создать функцию представления и шаблон для страницы ошибки 404. Сохраните этот код в 404.html и добавьте обработку ошибки 404 в mysite.py:
Примечание: Frozen Flask не станет экспортировать страницу 404, она будет работать только в «живой» версии Flask-приложения на сервере. На GitHub Pages кастомную страницу 404 придется создать вручную, мы сделаем это чуть позже.
Экспорт статической версии сайта
Когда работа над приложением и контентом окончена, нужно изменить значение site_url в settings.txt на название реального хоста, после чего можно приступать к экспорту статических страниц:
python mysite.py build
В ходе выполнения этой команды в корневой директории проекта будет создана папка build, содержащая «замороженную», статическую копию сайта. Чтобы проверить, не сломалось ли что во время экспорта, нужно запустить встроенный http-сервер из папки build:
python -m http.server
Если все в порядке, содержимое папки build можно загружать на хостинг.
Деплой на GitHub Pages
По правилам GitHub Pages, на одном аккаунте можно разместить один сайт username.github.io и сколько угодно сайтов username.github.io/site. После создания репозитория для сайта нужно найти пункт Pages в меню Code and automation и выбрать там branch/main и root:
Настройки репозитория для сайта
Нюансы GitHub Pages
Если сайт будет размещаться на username.github.io, в коде ничего менять не надо. В случае размещения сайта в проектной директории username.github.io/site нужно добавить название папки ко всем ссылкам на статические файлы. То есть вместо таких привычных ссылок:
Чтобы GitHub Pages показывал кастомную страницу ошибки 404 вместо стандартной, достаточно загрузить готовый файл 404.html в корневую директорию репозитория. Переадресацию хостинг обеспечит сам.
Подведем итоги
Простота, гибкость, наличие огромного количества расширений и удобный шаблонизатор – главные преимущества Flask. При работе над проектом модуль FlatPages избавил нас и от необходимости подключения базы данных, и от написания скрипта для конвертации Markdown-файлов в html. Модуль Frozen Flask обеспечил автоматический экспорт статической копии сайта без ущерба для функциональности. Реализация этих операций на каком-либо другом фреймворке потребовала бы куда больше кода и усилий. Напоминаем, что весь код проекта находится здесь, а готовый сайт доступен на GitHub Pages.
doing a to-do list – just for myself, decided to remember JS I have checkboxes and divs that are generated by themselves when a person enters text into an input. Checkboxes and divs have their own unique id (paired checkbox and div have th…
В этом выпуске: собеседование на позицию Junior фронтенд-разработчика, как фронтенд-разработчикам и дизайнерам найти общий язык, HTTP/3 был представлен в виде стандарта RFC 9114, обзор RedwoodJS за 100 секунд и еще четыре десятка полезных ссылок и новостей.
Новости
После более чем 5-ти лет кропотливой работы HTTP/3 был представлен в виде стандарта RFC 9114. Вместе с RFC 9204 (QPACK header compression) и RFC 9218 (Extensible Priorities) он открывает новую важную главу в истории Интернета. Узнать подробнее о протоколе HTTP/3
И действительно, в мире веб-разработки фреймворки приходят и уходят, но какой веб-сайт не возьми, там почти наверняка будет использоваться CSS. Что это за технология, которая с нами уже так долго, рассказывает София Валитова:
Перенос кодовой базы с Flow.js на Typescript: как это было в одном из сервисов компании Exness.
NodeJS
Виктор Хомяков из Яндекса рассказывает о видах проблем с памятью в браузерах и в Node.js, об ограничениях, которые часто упускаются из виду, и их преодолении.
Никита Улько, Flutter fullstack developer в Friflex, рассказывает об особенностях использования Flutter для веба.
Разбираемся с технологиями, которые используются браузером для повышения скорости загрузки веб-приложений: сканер предварительной загрузки и пропуск невидимого контента.
Собеседование на позицию Junior фронтенд-разработчика:
Изучаем основные принципы работы фреймворка, разрабатывая личный сайт с резюме, портфолио, блогом и контактной формой.
Flask – микрофреймворк: это означает, что в стандартную поставку входит только самое необходимое, а все остальное при необходимости легко подключается. Поэтому приставка «микро» не должна вводить в заблуждение – при желании на Flask можно реализовать серьезный, масштабируемый проект. А для реализации таких небольших веб-приложений, как наш сайт, Flask подходит как нельзя лучше.
Переключение между секциями создает иллюзию многостраничности, но в «живой» версии сайт – одностраничный. Бэкенд включает в себя модуль Frozen Flask, который превращает приложение в генератор статических сайтов (SSG): все страницы, необходимые для адекватного представления сайта в статической версии, создаются автоматически.
Готовый сайт на GitHub Pages
Фронтенд сделан на Bootstrap с несколькими дополнительными JS скриптами – например, записи в блоге фильтруются (без перезагрузки страницы) по тегам с помощью скрипта isotope.js, при этом теги для фильтра скрипт получает из расширения Flask – FlatPages. Записи в блоге и карточки в портфолио можно перелистывать свайпом, без перезагрузки страницы. Bootstrap обеспечивает адаптивность: сайт одинаково хорошо смотрится на широкоформатном мониторе и на смартфоне.
Первый этап
На этом этапе мы установим Flask вместе со всеми нужными расширениями и зависимостями, напишем первый вариант кода для блога и сделаем два простейших шаблона.
Установка Flask
Сначала нужно создать папку для проекта и активировать виртуальное окружение:
mkdir flask_project
cd flask_project
mkdir .venv
pipenv shell
Папка .venv – служебная: менеджер pipenv автоматически разместит все нужные зависимости там, и они не будут загромождать корневую директорию проекта. Виртуальное окружение активируется командой pipenv shell, для выхода нужно выполнить exit.
Установим Flask и все необходимые зависимости. Для этого сохраните этот список в файле requirements.txt:
В папке content/posts будут размещаться Markdown файлы, в templates – шаблоны, в static – CSS стили, изображения и JS-скрипты. Весь код приложения мы напишем в файле mysite.py – сначала импортируем нужные модули, затем определим основные параметры, после пропишем маршруты к шаблонам и запустим сервер. Простейший вариант кода mysite.py выглядит так:
import sys
from flask import Flask, render_template
from flask_flatpages import FlatPages, pygments_style_defs
from flask_frozen import Freezer
DEBUG = True
FLATPAGES_AUTO_RELOAD = DEBUG
FLATPAGES_EXTENSION = '.md'
FLATPAGES_ROOT = 'content'
POST_DIR = 'posts'
app = Flask(__name__)
flatpages = FlatPages(app)
freezer = Freezer(app)
app.config.from_object(__name__)
@app.route("/")
def index():
posts = [p for p in flatpages if p.path.startswith(POST_DIR)]
posts.sort(key=lambda item: item['date'], reverse=True)
return render_template('index.html', posts=posts, bigheader=True)
@app.route('/posts/<name>/')
def post(name):
path = '{}/{}'.format(POST_DIR, name)
post = flatpages.get_or_404(path)
return render_template('post.html', post=post)
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "build":
freezer.freeze()
else:
app.run(host='127.0.0.1', port=8000, debug=True)
В это трудно поверить, но основной код блога действительно занимает всего 28 строк. Это возможно благодаря модулям FlatPages и Flask Frozen: первый избавляет от необходимости хранить посты в базе данных, проводит рендеринг Markdown-файлов в html, обеспечивает вывод записей и обращение к их свойствам, что будет заметно при создании шаблонов. Flask Frozen в действии мы увидим чуть позже: этот модуль берет на себя создание статической копии сайта – экспортирует html-файлы и все нужные ассеты (скрипты, CSS, изображения) в папку build.
Добавим в папку posts два-три тестовых поста – в YAML части обязательно должны быть метаданные title, date, description, потому что Jinja будет вызывать их в шаблонах. Markdown посты можно писать в любом редакторе – хоть в Блокноте, хоть в Sublime Text; можно обзавестись и специальным редактором – MarkdownPad для Windows, Mou для macOS.
Теперь создадим два простейших шаблона. Это код для index.html:
Оба шаблона мы доработаем на следующем этапе, а пока запустим приложение python mysite.py и посмотрим на результат.
Главная страница блогаОтдельная запись
Весь код и тестовый контент для этого этапа есть здесь.
Второй этап
На этом этапе мы сделаем первые шаблоны и подключим файл с настройками.
Шаблонизатор Jinja2
Flask использует шаблонизатор Jinja2. Синтаксис Jinja2 идентичен шаблонизатору Django и напоминает Python. Если вам еще не приходилось работать с Django, на этом этапе достаточно знать, что логика в Jinja2 заключается в такие фигурные скобки {% %}, а переменные – в такие {{ }}.
Шаблон Jinja2 представляет собой обычный html-файл, в котором блоки с логикой и переменными размещаются в уже упомянутых скобках. К шаблону можно подключать любые JS-скрипты, иконки, шрифты. Большое количество переменных можно передать в шаблон в виде словаря:
@app.route("/")
def index():
variables = {"title":"Это мой сайт",
"description":"Разработчик, дизайнер, автор ИТ-курсов"
"keywords":"Разработка на Python, курсы по Django"
}
return render_template('index.html', **variables)
В шаблоне index.html, в свою очередь, эти переменные можно вставить в нужные теги:
Если же переменных очень много, имеет смысл вынести словарь в отдельный файл – в дальнейшем мы воспользуемся именно этим вариантом.
Jinja2 поддерживает наследование и включение шаблонов – это позволяет разбить шаблон объемной страницы на несколько секций, которые проще редактировать по отдельности. Наш сайт состоит из одной страницы с несколькими разделами, которые целесообразно вынести в отдельные шаблоны:
base.html
index.html
header.html
resume.html
counters.html
skills.html
interests.html
portfolio.html
card.html
blog.html
post.html
contacts.html
Jinja2 не диктует каких-то жестких правил: при желании можно обойтись всего двумя шаблонами – index.html и post.html. И, конечно, можно не выносить переменные в отдельный файл, а вписать весь текст резюме и портфолио прямо в index.html. Но поддерживать сайт проще, если хранить всю потенциально изменяемую информацию в Markdown-файлах и текстовом файле конфигурации – в этом случае для изменения данных нужно будет внести поправки только один раз: переменные в шаблонах обеспечат обновление текста во всех разделах сайта. Кроме того, ненужные разделы сайта очень просто удалить, если они находятся в отдельных шаблонах.
Первый шаблон, который мы создадим – base.html. Он будет получать переменные из бэкенда. Для передачи данных в шаблон создайте файл settings.txt и сохраните в нем словарь:
{"site_url":"http://localhost:8000",
"site_title": "John Doe: Python разработчик и автор контента",
"description": "Джон Доу - портфолио, резюме и блог Python разработчика",
"keywords": "Веб-разработка на Python, бэкенд на Django и Flask"}
Теперь добавьте импорт json и загрузку данных из файла в mysite.py:
@app.route("/")
def index():
posts = [p for p in flatpages if p.path.startswith(POST_DIR)]
posts.sort(key=lambda item: item['date'], reverse=True)
with open('settings.txt', encoding='utf8') as config:
data = config.read()
settings = json.loads(data)
return render_template('index.html', posts=posts, bigheader=True, **settings)
Весь код и контент для этого этапа – здесь. Во второй части туториала мы завершим работу над приложением и загрузим статическую копию сайта на GitHub Pages.
Всем привет, нужна помощь. Я делаю pomodoro timer и у меня возникла проблема в прибавлении числа из html к числу из js. В общем, когда я нажимаю на кнопу, число должно прибавляться на 1, но оно не меняется.
Вот код html:
“`
<!DOCTYPE h…
Всем привет, нужна помощь. Я делаю pomodoro timer и у меня возникла проблема в прибавлении числа из html к числу из js. В общем, когда я нажимаю на кнопу, число должно прибавляться на 1, но оно не меняется.
Вот код html:
“`
<!DOCTYPE h…
Имеется программа 350x500px и кнопка 30x5px, в которую пытаюсь впихнуть картинку. Но вместо картинки отображается белый прямоугольник и при чём не важно, в кнопке это изображение или нет, большая картинка или нет, просто белый прямоугольни…
В заключительной части туториала разберемся с автоматическим созданием профилей и уменьшением аватарок, реализуем CRUD, импортируем контент из json-файла и сделаем пагинацию.
На этом этапе мы займемся профилями пользователей и предоставим авторам возможность добавлять, редактировать и удалять свои записи со стороны фронтенда. Код для всех файлов этой части проекта находится здесь.
Сохранение изображений профилей
На предыдущем этапе мы уже создали модель для профиля и зарегистрировали ее. Теперь нужно обеспечить сохранение аватарок в нужной папке. По умолчанию Джанго создает папку profile_pics (для хранения аватарок) на одном уровне с папками приложений, что не слишком удобно.
Чтобы изменить расположение папки, откройте my_site\settings.py и добавьте в начало файла import os, а в конец вставьте:
Запустите сервер, войдите в панель управления – там уже есть раздел Profiles, причем количество профилей равно 0, хотя мы создали нескольких пользователей. Чуть позже мы рассмотрим, как автоматически создавать профили одновременно с регистрацией аккаунтов, а пока что создадим вручную один профиль для админа с аватаркой, и один профиль для пользователя без аватарки – вернее, у него будет аватарка по умолчанию default.jpg, которую вам нужно будет создать и поместить в папку media (но не внутрь profile_pics, а рядом).
Внесите изменения в шаблон профиля users\profile.html:
Осталось решить задачу с автоматическим созданием профилей во время регистрации. В Джанго для реализации такой логики существуют сигналы. Создайте файл users\signals.py и сохраните в нем этот код. Эти сигналы нужно импортировать в users\apps.py.
Проверим, как работает автоматическое создание профилей – запустим сервер и создадим новый аккаунт. Все получилось:
Теперь профили пользователей создаются автоматически
Пользователям нужна возможность самостоятельно вносить изменения в профиль – менять фото, ник и емейл, например. Для этого внесем дополнения в файл users\forms.py – добавим импорт from .models import Profile в начало и этот код в конец:
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email']
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['image']
Теперь пользователи могут изменять информацию в своих профилях:
Пользователи могут самостоятельно изменить ник, емейл и аватар
Автоматическое сжатие изображений
Если пользователи будут загружать слишком большие изображения, сервер скоро окажется перегруженным. Поэтому имеет смысл реализовать автоматическое сжатие изображений, используемых в качестве аватарок. Такую возможность предоставляет библиотека Pillow, которую мы уже использовали. Для сжатия фото с помощью Pillow в users\models.py нужно сохранить этот код. Теперь крупные изображения уменьшаются автоматически.
Отображение аватарок в постах
Пока что изображения пользователей видны только в их профилях. Чтобы фото авторов отображались в постах блога, внесем дополнения в шаблон blog\home.html – сохраните в нем этот код. Аватарка пользователя теперь показывается в посте:
Аватарка автора отображается рядом с его записями
CRUD
Чтобы дать возможность пользователям управлять постами, нужно реализовать CRUD – набор операций по созданию, редактированию и удалению контента. Создать такую функциональность будет проще, если перейти от функций представления к классам. Для этого нынешнее содержимое файла blog\views.py нужно изменить на это, а код blog\urls.pyдолжен выглядеть так. Обратите внимание на классы PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView) и PostDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView) – они обеспечивают создание, редактирование и удаление записей только зарегистрированными пользователями; при этом редактировать и удалять посты могут лишь их авторы.
Для просмотра отдельных постов создадим шаблон post_detail.htmlвот с таким кодом. Теперь каждый пост можно открыть отдельно: http://localhost:8000/post/1/. Добавим эту возможность в шаблон home.html:
После создания записи следует перенаправить пользователя на отдельную страницу поста. Для этого измените существующий код blog\models.pyна этот, и все заработает:
Отдельная страница для каждой записи
Записи уже можно обновлять, но пока что нельзя удалять. Создадим нужный шаблон – файл blog\post_confirm_delete.html. Код для него есть здесь. Теперь удаление работает, после подтверждения удаления запись исчезает, а пользователь перенаправляется на главную страницу блога:
Подтверждение удаления
Осталось добавить ссылку на создание новой записи на панель навигации – мы сделаем это в шаблоне base.html, добавив всего одну строку<a class="nav-item nav-link" href="{% url 'post-create' %}">Новая запись</a>. Все готово! Если что-то не работает, сверьтесь с готовым кодом к третьему этапу.
Четвертый этап разработки
На заключительном этапе работы над проектом мы загрузим контент из json файла (с помощью интерактивной консоли Django), сделаем пагинацию и обеспечим вывод всех постов автора на отдельной странице.
Импорт контента из файла json
Создавать посты от имени нескольких авторов утомительно, поэтому мы воспользуемся загрузкой контента из готового файла posts.json. Запустим интерактивную консоль Джанго python manage.py shell и проведем импорт. Отступы в консоли – 2 вместо обычных 4:
>>> import json
>>> from blog.models import Post
>>> with open('posts.json', encoding="utf8") as f:
... posts_json = json.load(f)
...
>>> for post in posts_json:
... post = Post(title=post['title']), content=post['content'], author_id=post['user_id']
... post.save()
...
>>> exit()
Теперь на нашей главной странице отображается множество записей.
Пагинация
Пора реализовать пагинацию – разбиение постов на страницы. Для разделения постов на страницы внесем изменения в класс PostListView(ListView) в файле blog\views.py – добавим строку paginate_by = 5. Отредактируем шаблон home.html – разместим логику пагинатора между {% end for %} и {% end block content%} в конце файла. Записи теперь разделены на страницы:
Пагинатор разделяет записи по 5 постов на странице
Еще было бы здорово показывать на странице пользователя все записи, которые он создал – с пагинацией, если записей много. Для этого мы добавим в blog\views.py импорт get_object_or_404 и новый класс:
class UserPostListView(ListView):
model = Post
template_name = 'blog/user_posts.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts'
paginate_by = 5
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(author=user).order_by('-date_posted')
Поэтапное создание простого веб-приложения дает возможность быстро освоить основные принципы разработки в Django. Фреймворк позволяет достаточно просто реализовать сложную функциональность – например, CRUD, – а соответствующие библиотеки помогают разрабатывать формы и автоматически сжимать изображения. Напоминаем, что код для всех этапов проекта доступен здесь.
Во второй части туториала будем разрабатывать систему регистрации и авторизации, а также ограничим доступ к просмотру профилей для неавторизованных посетителей блога.
Продолжим работу над проектом с создания первой учетной записи для админа, а затем перейдем к разработке необходимых моделей для базы данных и форм регистрации / авторизации. Весь код второго этапа находится здесь.
Создание учетных записей и администрирование
Панель администрирования открывается по адресу http://localhost:8000/admin. Пока что войти в админку нельзя: сначала нужно создать учетную запись суперпользователя (админа). Перед началом этого процесса следует применить миграции: python manage.py migrate (эту операцию мы намеренно пропустили на первом шаге).
После применения миграций можно приступать к созданию записи для суперпользователя: python manage.py createsuperuser
В ходе выполнения команды появится приглашение ввести имя пользователя, пароль и емейл (они не отображаются во время ввода – будьте внимательны). Учетная запись суперпользователя готова, запустите сервер и авторизуйтесь:
Учетная запись администратора
Кликните по ADD USER и создайте учетные записи для двух тестовых пользователей. Обратите внимание, что Джанго берет хэширование паролей на себя:
Аккаунт тестового пользователя
Примечание: если вы забыли пароль суперпользователя, его можно сменить так: python manage.py changepassword <имя пользователя>.
Работа с базой данных и моделями
Одна из сильнейших сторон Джанго – простота подключения базы данных и возможность работать с любыми базами с помощью одного и того же кода (и без глубоких познаний в области языка запросов SQL). Django уже создал для нас файл models.py. Каждая модель представляет отдельную таблицу в базе. Откроем models.py и напишем код для модели Post.
Для обновления структуры базы создадим и выполним миграции: сначала запустим python manage.py makemigrations, а затем python manage.py migrate.
Теперь пора обновить файл blog\views.py, в котором на первом этапе мы записали тестовый контент. Для обработки реального контента из модели Post код должен выглядеть так.
Чтобы модель для создания новых записей отображалась в панели администрирования, ее нужно зарегистрировать в файле blog\admin.py:
from django.contrib import admin
from .models import Post
admin.site.register(Post)
Как уже упоминалось, приложения из проекта можно использовать отдельно – вставить блог, например, в другой проект. Поэтому и систему регистрации / авторизации стоит реализовать отдельно. Запустим Джанго-команду для создания нового приложения под названием users: python manage.py startapp users. После этого нужно зарегистрировать новое приложение, как мы уже делали с блогом. Сначала откройте my_site\settings.py и добавьте нужную строку в список INSTALLED_APPS:
В этом же файле в самом низу добавьте ссылку на стили Bootstrap для форм:
CRISPY_TEMPLATE_PACK = 'bootstrap4'
Модуль django-crispy-forms не входит в стандартный дистрибутив Джанго – скорее всего, вам потребуется его установить: pipenv install django-crispy-forms.
Затем откройте users\views.py и сохраните в нем код:
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import UserRegisterForm
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Создан аккаунт {username}!')
return redirect('blog-home')
else:
form = UserRegisterForm()
return render(request, 'users/register.html', {'form': form})
Для формы регистрации нам потребуется соответствующий шаблон. Как и в случае с блогом, создайте в папке users директорию templates, в ней – поддиректорию users, а в ней файл register.html. Код шаблона будет таким.
Внесем нужные изменения в url-паттерны. Откройте my_site\urls.py и добавьте в него импорт users_views и маршрут к форме регистрации:
from django.contrib import admin
from django.urls import path, include
from users import views as user_views
urlpatterns = [
path('admin/', admin.site.urls),
path('register/', user_views.register, name='register'),
path('', include('blog.urls')),
]
Теперь создайте файл users\forms.py и сохраните в нем этот код, после чего добавьте отображение сообщения об успешной регистрации в шаблон блога base.html, прямо над блоком контента {% block content %}{% endblock %}:
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
Зарегистрируем нового пользователя NewUser и получим сообщение об успешной регистрации аккаунта. Проверим панель администрирования http://localhost:8000/admin/auth/user/ – новая учетная запись там появилась, значит, форма работает правильно. Попробуйте ввести некорректные регистрационные данные – форма проводит валидацию самостоятельно, без всяких дополнительных усилий с нашей стороны:
Форма неплохо справляется с валидацией
Вход и доступ к профилям для зарегистрированных пользователей
Одно из главных преимуществ системы авторизации – возможность показывать определенный контент только зарегистрированным пользователям. Сначала мы создадим логику и страницы входа и выхода, а затем перейдем к вопросу ограничения доступа для неавторизованных и/или незарегистрированных пользователей.
Чтобы управлять профилями в админ-панели, нужно зарегистрировать модель в admin.py:
from django.contrib import admin
from .models import Profile
admin.site.register(Profile)
Создайте шаблон для страницы профиля – profile.htmlв templates/users, и сохраните этот код в users\models.py. Код модели использует библиотеку для работы с изображениями Pillow. Установите ее в виртуальное окружение проекта: pipenv install pillow. Создайте и примените миграции:
Теперь можно запускать сервер – у нас уже есть работающие страницыhttp://localhost:8000/login/ иhttp://localhost:8000/logout/; на страницу login выполняется переадресация после регистрации. Если сейчас ввести некорректный логин, появится сообщение об ошибке. Но и ввод верных данных приведет к ошибке 404 – приложение пытается открыть профиль пользователя, но у него пока что нет правильного маршрута к странице. На самом деле, и переадресация на профиль после входа на сайт выглядит странно – гораздо логичнее перенаправить пользователя на главную страницу блога, что мы и сделаем.
Займемся переадресацией – откроем my_site\settings.py и добавим переадресацию в конце файла:
LOGIN_URL = 'login'
Теперь, если вы введете верный логин и пароль, произойдет переадресация на главную страницу блога. Пока что визуально это не слишком очевидно – ссылки на панели навигации не соответствуют тому, вошел ли пользователь на сайт или нет – но мы сейчас это исправим.
Прежде всего, внесем изменения в шаблон base.html – найдите правый блок навигации и вставьте этот код между тегами <div class="navbar-nav"></div>:
Если зайти на сайт с правильным логином и паролем, можно увидеть свой профиль – правда, пока без аватарки:
Профиль без изображения пользователя
Последнее, что мы сделаем на этом этапе – обеспечим ограничение доступа к профилям для незарегистрированных пользователей. Для этого в файл users\views.py нужно добавить декоратор @login_required:
Если неавторизованный пользователь теперь попытается открыть страницу профиля, он будет переадресован на страницу входа на сайт. Напоминаем: весь код, созданный на этом этапе работы, находится здесь.
Промежуточные итоги
В этой части туториала мы реализовали систему авторизации в виде отдельного приложения, которое в дальнейшем можно будет использовать в любом другом Django-проекте. Дополнительной функциональностью для управления профилями мы займемся в следующей, заключительной части.
Обзор нововведений Angular 14, подборка игровых площадок для изучения веб-разработки, 7 полезных расширений VS Code для React-разработчика, анонс самого большого обновления Next.js, лучшие практики по работе с Node.js и многое другое.
Vue 3: обзор различных вариантов взаимодействия компонентов.
Книга Fullstack Vue (2018), Автор: Hassan Djirdeh
Цель этой книги – стать единственным наиболее полезным ресурсом по обучению Vue.js . К тому времени, когда вы закончите читать эту книгу, у вас будет все необходимое для создания надежных, мощных приложений на Vue.
После прочтения первых нескольких глав вы получите четкое представление об основах Vue и сможете создавать широкий спектр интерактивных веб-приложений с помощью фреймворка.
Анонс самого большого обновления Next.js с момента его появления в 2016 году. Часть 1: обзор новой системы маршрутизации и ее интеграции с компонентами React Server и сбором данных.
JavaScript, CSS и HTML
Подборка малоизвестных и малоиспользуемых функций CSS в 2022 году, которая составлена с учетом мнения сообщества и личного взгляда автора статьи.
Современная отзывчивая типографика с использованием CSS clamp: полный гайд от теории к практике. En и Ру.
for-of vs. .reduce() vs. .flatMap(): сравнение трёх способов обработки массивов в JavaScript, которое поможет выбрать наиболее подходящий вариант для вашей работы.
Слайдер, который выглядит одинаково во всех браузерах: разбираем псевдоэлементы и префиксы свойств, на которые следует ориентироваться.
Коллекция сниппетов на JavaScript и CSS для ежедневных потребностей фронтенд-разработчика.
Собираетесь изучать Django, но не знаете, с чего начать? Расскажем, как быстро создать функциональное приложение, которое продемонстрирует базовые возможности фреймворка.
В первой части туториала мы установим Django, создадим структуру будущего веб-приложения и покажем, как работают шаблоны. Готовый код поможет буквально за полчаса разобраться в логике и принципах работы фреймворка.
Обзор проекта
Мы создадим многопользовательский блог для клуба любителей задач Python Bytes. Вместе со стандартным пакетом Django будем использовать модули django-crispy-forms и Pillow. Реализуем всю функциональность, необходимую для:
регистрации и авторизации участников;
автоматического создания пользовательских профилей;
заполнения и изменения информации в профилях;
автоматического сжатия изображений для аватарок;
создания, редактирования и удаления записей со стороны фронтенда;
пагинации и вывода записей на страницах авторов.
Готовое приложение
Установка Django
Установим Django в виртуальное окружение с помощью менеджера pipenv:
Размер пакета – чуть менее 9 Мб. Команда pipenv install django установит Django самой последней версии. Если нужна одна из предыдущих версий, следует явно указать ее номер: pipenv install django==3.2
Виртуальное окружение активируют командой pipenv shell, после чего перед названием директории появляется (.venv).
В дальнейшем перед началом работы над проектом нужно каждый раз активировать виртуальное окружение этой же командой, pipenv shell.
Создание проекта
Для автоматической генерации структуры и управляющих скриптов проекта выполняют команду: django-admin startproject my_site .
После чего папка my_site с базовой структурой появится в директории Django. Точка после команды предотвращает создание дополнительной вложенной папки в my_site. С другой стороны, если не использовать точку, все разрабатываемые приложения будут вложены в папку конкретного проекта, и во многих случаях такая структура удобнее, поскольку каждый проект может содержать множество приложений – блог, онлайн-магазин и т. д. Очень полезная особенность Django состоит в том, что все эти приложения будут вполне независимыми друг от друга, и например, однажды разработанный блог или магазин можно будет без проблем вставить в другой проект.
После создания проекта можно запустить сервер python manage.py runserver и открыть страницу в браузере:
Django успешно установлен
При этом в терминале наверняка появится сообщение вроде этого:
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Пока что ничего с ним делать не нужно.
Первый этап разработки
На этом этапе мы создадим базовую структуру приложения, функции представления и маршруты, подключим шаблоны и добавим тестовый контент. Все файлы для этого этапа находятся здесь– если что-то неясно, просто скопируйте код из них полностью, и все заработает.
Создание приложения, представлений и маршрутов
Чтобы создать папку и базовую структуру для будущего приложения, выполните python manage.py startapp blog. Название приложения не должно совпадать с названием папки проекта, иначе возникнет ошибка:
CommandError: '%app%' conflicts with the name of an existing Python module and cannot be used as an app name. Please try another name.
То есть если вы назвали папку проекта my_site, приложение должно называться по-другому – например, blog. Чтобы посмотреть структуру проекта с вложенными в него приложениями, выполните tree.
Теперь открываем файл blog\view.py. Здесь располагаются функции представления, которые обеспечивают функционирование логики приложения. В файле уже есть одна строка from django.shortcuts import render. Добавим обработку https запросов и функции представления для страниц Главная и Наш клуб. В итоге содержимое должно выглядеть так:
from django.shortcuts import render
from django.http import HttpResponse
def home(request):
return HttpResponse('<h1>Главная</h1>')
def about(request):
return HttpResponse('<h1>Наш клуб</h1>')
Это тестовый код, в дальнейшем мы его изменим.
Теперь в папке blog создадим файл urls.py, чтобы приложение могло сопоставить маршруты и страницы. Добавим туда код:
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='blog-home'),
path('about/', views.about, name='about-club'),
]
После этого откройте файл urls.py, который находится в папке проекта my_site и добавьте в импорт include, а в urlpatterns – путь к ссылкам приложения blog:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('blog.urls')),
]
Строка path('', include('blog.urls')) делает страницу блога домашней (главной). Если же блог является лишь одним из разделов портала, следует явно указывать маршрут к нему: path('blog', include('blog.urls')).
Запустим сервер python manage.py runserver и откроем адреса http://localhost:8000/ и http://localhost:8000/about/ – все работает: на домашней странице выводится надпись Главная, на странице about.html – название нашего клуба.
Чтобы страницы выглядели интереснее, чем простые надписи на белом фоне, нужно подключить шаблоны. По умолчанию Джанго будет искать шаблоны в папке templates директории blog. Создадим templates, a внутри нее поддиректорию с тем же названием, что и приложение – blog. Это стандартная практика: так Django понимает, что шаблоны относятся именно к приложению blog. Внутри папки templates\blog создайте три файла base.html, home.html и about.html. Сохраните в них код, который нужно взять здесь: base.html; home.html; about.html.
На одном уровне с templates создайте папку static, а внутри нее еще одну одноименную с приложением поддиректорию blog – в ней будeт размещаться css-файл main.css, который переопределяет стили Bootstrap. Подробный процесс создания шаблонов выходит за рамки этого туториала. На этом этапе достаточно знать, что шаблоны в Джанго состоят из комбинации html, css, JavaScript, логики и переменных, которые заключаются в фигурные скобки {% %} и {{ }} соответственно.
Рассмотрим несколько примеров.
Шаблон home.html начинается с {% extends "blog/base.html" %} – потому что основным шаблоном является base.html: в нем подключены стили, скрипты и шрифты. Чтобы не повторять этот код многократно, используется наследование, и шаблон home.html расширяет base.html, используя весь его код.
Блоки контента (шаблон может получать контент из других шаблонов) заключаются в скобки с процентным символом {% %}:
{% block content %}
{% endblock %}
В отличие от Python, шаблонизатор Django нуждается в четком указании на окончание цикла:
{% for post in posts %}
{% endfor %}
То же самое касается условий:
{% if object.author == user %}
{% endif %}
Условия и циклы, как и в Python, можно комбинировать:
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
Шаблонизатор использует свою систему фильтров данных по самым разным критериям; фильтр объявляется символом |:
{{ post.date_posted|date:"F d, Y" }}
Переменные, которые Django получает из функций, классов или файлов конфигурации, вводятся в шаблон при помощи двойных фигурных скобок:
{{ post.author }}
{{ title }}
{{ object.author }}
Логика шаблонизатора Django напоминает Python, но все же отличается от него. Для создания шаблона не нужно обладать всеми навыками фронтендера – всегда можно воспользоваться готовым Bootstrap шаблоном. Достаточно знать, как вставлять в готовые html-шаблоны логику и переменные, и как происходит наследование шаблонов и включение фрагментов контента из одного шаблона в другие. Наш шаблон основан на Bootstrap 4: ссылка на соответствующую версию подключается в head.
Базовая настройка конфигурации
Теперь займемся конфигурацией. Откройте файл blog\apps.py и скопируйте оттуда название класса BlogConfig. Это название нужно вставить в файл settings.py нашего проекта my_site, как показано ниже:
Откройте blog\views.py. Добавим тестовый контент и обработку шаблонов:
from django.shortcuts import render
posts = [
{
'author': 'Администратор',
'title': 'Это первый пост',
'content': 'Содержание первого поста.',
'date_posted': '12 мая, 2022'
},
{
'author': 'Пользователь',
'title': 'Это второй пост',
'content': 'Подробное содержание второго поста.',
'date_posted': '13 мая, 2022'
}
]
def home(request):
context = {
'posts': posts
}
return render(request, 'blog/home.html', context)
def about(request):
return render(request, 'blog/about.html', {'title': 'О клубе Python Bytes'})
Шаблон home.html уже содержит ссылки на переменные, перечисленные в списке словарей posts. Запустим сервер и оценим работу шаблонов home.html и about.html. Напоминаем, что весь код для этого этапа можно взять здесь.
Вывод тестового контента
Подведем промежуточные итоги
У нас есть скелет приложения и основные шаблоны. На следующем этапе мы займемся администрированием, созданием учетных записей и ограничением доступа для неавторизованных пользователей.
Запускаю свой проект в локальном сервере через "node index.js."
Есть index.ejs файл где я соединяю скрипт "login.js":
<header class="header layer">
<div class="header__container conta…
Чтобы программирование на JavaScript было быстрым и эффективным с нуля, воспользуйтесь нашей дорожной картой.
— Читать дальше «Разработка на JavaScript с нуля в 2022 году: дорожная карта»
…
Первый выпуск посвящен фронтенду: шпаргалка по основным концепциям React, реализация шагающей игрушки слинки на чистом CSS, руководство по TypeScript для начинающих, интервью «Как инженеру не умереть со скуки во фронтенде» и еще четыре десятка полезных ссылок.
В этом ролике ты разработаешь свои шахматы на React, Typescript и попрактикуешь ООП:
Шахматы на React и TypeSctipt с нуля
Remotion — инструмент, который позволяет создавать видео с использованием React. Недавно у инструмента вышло (https://www.remotion.dev/blog/3-0) большое обновление, которое включает Remotion Lambda. Это позволяет пользователям развертывать и размещать видео непосредственно в своих учетных записях AWS, что намного быстрее, дешевле и масштабируемее, чем Remotion 2.0.
Учебник The React beginners handbook — Flavio Copes:
Учебник The React beginners handbook — Flavio Copes
Курс, посвящённый основам JavaScript, CSS и HTML от специалистов Azure Cloud Advocates из Microsoft включает 24 урока и рассчитан на 12 недель (некоторые уроки переведены на русский). Каждый урок содержит тесты до и после урока, задание, решение, письменные инструкции по завершении урока и многое другое (GitHub, GitHub Pages).
quick-lint-js — линтер для JavaScript-кода, который быстрее, проще и дружелюбнее ESLint.
Реализация шагающей игрушки слинки на чистом CSS. Интересные подходы и приемы CSS-анимации в пошаговом руководстве.
6 кейсов HTML и CSS, которые многие разработчики упускают из виду.
Больше CSS-комиксов и других полезных материалов здесь. А ещё есть YouTube-канал автора комиксов, где можно научиться этому и не только.
Обзор основных концепций ООП с примерами на JavaScript.
Текстовая расшифровка доклада о состоянии CSS в 2022 году на недавней конференции Google IO.
Миграция крупного проекта с Flow на TypeScript: как это было в команде Stripe.
NodeJS
sdc-check — легковесный инструмент для выявления рисков в ваших npm-зависимостях и обеспечения превентивных мер защиты.
Разное
Главные болевые точки веб-разработчика в 2022 году. Автор статьи кратко представил обновлённые данные двух кварталов текущего года относительно прошлого и обобщил мысли более 18-ти разработчиков по данной теме. В общем, получилось любопытно.
Из маркетинга во фронтенд-разработку: как это было.
Свежие комментарии