Category: Frontend

04
Июл
2022

📰 Weekly #7: новости, подкасты, отборные статьи и обучающие материалы по фронтенду

В этом выпуске: советы по недопущению ошибок в коде на React; неофициальные переводы руководств Google по стилю написания кода на JavaScript и TypeScript; 10 полезных приемов для работы с CSS; функции высшего порядка в JavaScript (гайд для новичков).

Новости

React

JavaScript, CSS и HTML

  • Нужна ли регулировка размера текста в CSS-библиотеках для сброса стилей? Разбираем 7 вариантов
  • Svelte Origins: A JavaScript Documentary. Если у вас все в порядке с английским, этот фильм для вас. Документальный фильм рассказывает историю о том, как появился Svelte, что отличает Svelte и как он меняет игру как JavaScript-фреймворк. В фильме, снятом в разных местах Европы и США, участвуют создатель Svelte Рич Харрис и члены сообщества, которые внесли свой вклад в Svelte и сделали его тем, чем он является сегодня.

TypeScript

NodeJS

  • Второй выпуск “Аффтарпати” посвящён JavaScript. Гостем стал Тимур Шемсединов – мощный JS-разработчик, гуру Node.js. Темы выпуска: ФП, разработка бэкенда на JS, образование и много чего ещё:

Разное

  • Шпаргалка в формате вопрос-ответ, в которой собраны основные интерфейсы и методы для работы с медиа в браузере.
***

Предыдущие выпуски

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека фронтендера»

29
Июн
2022

Не подключается js файл в html

Не судите строго если проблема глупая.
Выучил основы JavaScript и продолжаю путь изучая React. Я почти всегда использую отдельно html и отдельно js файлы. Начав учить React, в туториале всегда js пишется в html файле, и нет инструкций как …

29
Июн
2022

🧩 35 браузерных плагинов для Google Chrome в помощь разработчику

Ловите подборку расширений и плагинов для браузера, облегчающих жизнь программисту: ответы со StackOverflow в виде кода в топе выдаче Google, вызов, обнаружение и тестирование HTTP и REST API, анализатор UX, уменьшение потребления памяти Ch…

23
Июн
2022

Как перезаписать вывод данных из массива в html? После вывода нового значения из массива, старое убиралось по нажатию на кнопку и так далее

let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

let radioName = [“Radio-1”, “Radio-2”, “Radio-3”];
let radioNumber = [“85.5”, “90”];

// let currentIndex = 0;
// let currentLimit = 1;

secondBtn.onclick = function showArray() {
currentLi…

23
Июн
2022

📱 Ionic vs React Native: ключевые различия, о которых следует знать перед началом работы

Для разработки мобильных приложений требуется, чтобы оно работало на разных операционных системах и чтобы не переписывать код под отдельную операционную систему используют фреймворки.
В этой статье расскажем о двух таких фреймворках: Ionic и React Native.

Что такое кроссплатформенное создание приложений

Кроссплатформенное создание приложений – это способ создать приложение под все мобильные ОС.

Что такое Ionic

Ionic – это стартап Бена Сперри и Макса Линча, которые работали в разных стартапах, а потом основали компанию Drifty development company. Они предложили свое собственное решение – кроссплатформенный инструмент разработки, основанный на веб-технологиях.

Ionic встраивается в HTML, CSS, а последние версии фреймворка позволяют разработчикам использовать любой из фреймворков пользовательского интерфейса JavaScript: Angular, React или Vue.

Ionic на GitHub: github.com/ionic-team/ionic-framework

Преимущества Ionic

  1. Встроенные стили UI элементов. Их можно использовать прямо из фреймворка.
  2. Быстрый цикл разработки-тестирования. Код можно тестировать в браузере, не нужны эмуляторы смартфонов.
  3. Легко изучить. Требуются знания Angular, React или Vue, чтобы начать работать.
  4. Имеется сервисная поддержка.

Недостатки Ionic

  1. Ограничения производительности. Производительность приложений на Ionic ниже по сравнению с нативными приложениями.
  2. Разработчики утверждают, что каждая новая версия Ionic содержит ошибки. Но команда разработки не оставляет этот факт без внимания.
Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека мобильного разработчика»

Примеры приложений на Ionic

Untappd

Untappd – социальная сеть для более чем 4 миллионов любителей пива (GooglePaly, Github автора)

Скриншот приложения Untappd в GooglePlay
Скриншот приложения Untappd в GooglePlay

Marketwatch

Marketwatch – приложение для новостей и анализа рынка (AppStore, GooglePlay).

Основатели не афишируют себя.

Скриншот приложения MarketWatch в GooglePlay
Скриншот приложения MarketWatch в GooglePlay

Что такое React Native

React Native – это кроссплатформенная платформа разработки, которая позволяет создать приложение максимально приближенное к нативному, используя большую часть кодовой базы для разных платформ: Android и iOS. React Native – это продукт от Facebook*.

React native на GitHub github.com/facebook/react-native

Возможности React Native

  1. Использует JavaScript независимо от платформы. Кроме того, при необходимости вы можете использовать собственные модули в Objective-C, Swift, Java или Kotlin.
  2. Высокая производительность. Код работает на собственном API.
  3. Фреймворк предлагает готовые компоненты пользовательского интерфейса: кнопки, модули, ползунки. Это сокращает время, необходимое для разработки пользовательского интерфейса приложения.
  4. Позволяет вводить новые версии в запущенное приложение без потери текущего состояния.
  5. Бесплатное использование.

Недостатки React Native

  1. Более длительное время разработки. В отличии от Ionic, нужно создавать пользовательскую версию каждого экрана для каждой платформы.
  2. Поскольку время на разработку в React Native больше, могут потребоваться дополнительные инвестиции.
  3. В React Native можно использовать модули, написанные не только на JavaScript. Поэтому требуется поддержка специалистов по другим языкам. И в результате возрастает стоимость разработки. Но этим недостатком можно пренебречь, если использовать один язык программирования.
  4. Размер приложений на React Native больше, чем у приложений на Java или Kotlin.

Примеры приложений на React Native

Instagram**

Знаменитая социальная сеть с фотографиями, историями, личными сообщениями, рекламным кабинетом (AppStore, GooglePlay).

Скриншот приложения Instagram в GooglePlay
Скриншот приложения Instagram в GooglePlay
*, ** Продукт Meta, деятельность признана экстремистской, запрещена на территории России.

Bloomberg

Медиакомпания, которая поставляет информацию участникам финансового рынка (AppStore, GooglePlay).

Скриншот приложения Bloomberg в GooglePlay
Скриншот приложения Bloomberg в GooglePlay

Walmart

Американская сеть оптовой и розничной торговли (AppStore, GooglePlay).

Скриншот приложения Walmart в GooglePlay
Скриншот приложения Walmart в GooglePlay

Ionic vs React Native: ключевые различия

React Native Ionic
Стек технологий Обязательно владеть JavaScript и React.js Базовые знания HTML/CSS, JavaScript и любых доступных фреймворков: Angular, React или Vue
Обучение Если вы новичок в React, понадобится знать Java, Kotlin, Swift, Objective-C Достаточно базовых навыков
Возможность повторного использования кода Можно использовать для устройств Android и iOS. Но может потребоваться небольшой фрагмент кода, специфичного для конкретной платформы Можно использовать один и тот же код для любых платформ, устройств и операционных систем
Тестирование кода Тестирование проводится в эмуляторе Тестирование проводится в браузере
Визуализация Визуализация проводится в реальном времени Приложение обновляется после внесения изменений
Производительность Производительность приложения React Native максимально приближена к нативной Приложения, созданные с помощью Ionic, работают немного медленнее

Как выбрать фреймворк

Вам нужен React Native

  1. Если у вас уже есть веб-сайт на основе React, или ваша команда разработчиков хорошо разбирается в React.
  2. Если высокая производительность является для вас в приоритете.
  3. Если у вас достаточно времени и вы готовы вложить его в разработку приложения React.
  4. Если у вас есть ресурсы на труд разработчиков других языков.

Вам нужен Ionic

  1. Если вы планируете запустить стартап.
  2. Если вы сосредотачиваетесь на разработке MVP, чтобы собрать средства для будущего роста.
  3. Если для вас важно время для разработки.
  4. Ваш бюджет ограничен, и вы хотели бы минимизировать расходы, прежде чем ваш MVP привлечет инвестиции.
***

Материалы по теме

22
Июн
2022

🐍🥤 Flask за час. Часть 2: завершаем разработку и размещаем сайт на GitHub Pages

Создаем разделы «Резюме», «Портфолио», «Блог», «Контакты», экспортируем статические страницы и заливаем сайт на хостинг.

Третий этап

На этом этапе мы сделаем и включим в index.html шаблоны resume.html, counters.html, skills.html, interests.html, которые составляют секцию «Резюме» и portfolio.html – для, соответственно, раздела «Портфолио».

Для начала сохраните этот код в index.html:

        {% extends "base.html" %}
{% block content %}
{% block header %}
{% include "header.html" %}
{% endblock %}
{% block resume %}
{% include "resume.html" %}
{% endblock %}
{% block counters %}
{% include "counters.html" %}
{% endblock %}
{% block skills %}
{% include "skills.html" %}
{% endblock %} 
{% block interests %}
{% include "interests.html" %}
{% endblock %}
{% endblock %}

    

Создайте шаблоны resume.html, counters.html, skills.html, interests.html. Фото автора для резюме поместите в static/img. Обновите страницу – раздел «Резюме» полностью готов:

Секция резюме состоит из 4 шаблонов
Секция резюме состоит из 4 шаблонов

Последнее, что мы сделаем на этом этапе – шаблон для секции «Портфолио». Код для шаблона возьмите здесь – portfolio.html. Не забудьте включить портфолио в index.html:

        {% block portfolio %}
{% include "portfolio.html" %}
{% endblock %}

    

Первая версия портфолио готова – мы доработаем ее на следующем этапе:

Карточки проектов скоро будут открываться
Карточки проектов скоро будут открываться

Весь код и контент для третьего этапа есть здесь.

Четвертый этап

На заключительном этапе мы реализуем просмотр карточек проектов в портфолио, а затем сделаем секцию блога, контактную форму и страницу 404.

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека питониста»

Карточки портфолио

Вся базовая информация о проектах (название и краткое описание) пока что находится прямо в шаблоне 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)

    

И добавьте маршрут к карточкам портфолио:

        @app.route('/portfolio/<name>/')
def card(name):
	path = '{}/{}'.format(PORT_DIR, name)
	card = flatpages.get_or_404(path)
	return render_template('card.html', card=card)

    

Осталось сделать шаблон для карточек 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
Фильтрация по тегу 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:

        {% block contacts %}
{% include "contacts.html" %}
{% endblock %}

    

Наш сайт будет размещаться на хостинге GitHub Pages, который не поддерживает Flask (и вообще поддерживает только Jekyll с ограниченным набором плагинов). Поэтому разместить там можно только статическую копию сайта, которую сгенерирует модуль Frozen Flask. В статическом режиме, естественно, обработка формы работать не будет. Но возможность подключения внешнего обработчика к формам на статических сайтах существует. Мы воспользуемся услугами одного из таких сервисов – Formspree. Полученную после регистрации ссылку нужно вставить в код формы:

        <form action="https://formspree.io/f/mayvolep"  method="post" role="form" class="eform mt-4">
    
Обработку формы берет на себя внешний сервис
Обработку формы берет на себя внешний сервис

Теперь можно получать сообщения от посетителей сайта:

В платной версии есть переадресация после отправки
В платной версии есть переадресация после отправки

Посетитель увидит уведомление об отправке, а владелец сайта получит сообщение на емейл, указанный при регистрации. Formspree фильтрует спам. Другие подобные сервисы по обработке форм на статических сайтах – 99Inbound и KwesForms.

Страница 404

Осталось создать функцию представления и шаблон для страницы ошибки 404. Сохраните этот код в 404.html и добавьте обработку ошибки 404 в mysite.py:

        @app.errorhandler(404)
def page_not_found(e):
	return render_template('404.html'), 404

    
Примечание: 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 нужно добавить название папки ко всем ссылкам на статические файлы. То есть вместо таких привычных ссылок:

        <link href=" /static/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href=" /static/assets/bootstrap-icons/bootstrap-icons.css" rel="stylesheet">
<link href=" /static/assets/boxicons/css/boxicons.min.css" rel="stylesheet">
<link href=" /static/assets/glightbox/css/glightbox.min.css" rel="stylesheet">
...
<script src=" /static/assets/swiper/swiper-bundle.min.js"></script>
<script src=" /static/assets/waypoints/noframework.waypoints.js"></script>
<script src=" /static/js/main.js"></script>

    

должны быть такие:

        <link href="/flask_site/static/assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/flask_site/static/assets/bootstrap-icons/bootstrap-icons.css" rel="stylesheet">
<link href="/flask_site/static/assets/boxicons/css/boxicons.min.css" rel="stylesheet">
<link href="/flask_site/static/assets/glightbox/css/glightbox.min.css" rel="stylesheet">
...
<script src="/flask_site/static/assets/swiper/swiper-bundle.min.js"></script>
<script src="/flask_site/static/assets/waypoints/noframework.waypoints.js"></script>
<script src="/flask_site/static/js/main.js"></script>

    

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

        <a href="posts/login_in_django/"
<a href="portfolio/java_go/"

    

Кастомная страница для GitHub Pages

Чтобы GitHub Pages показывал кастомную страницу ошибки 404 вместо стандартной, достаточно загрузить готовый файл 404.html в корневую директорию репозитория. Переадресацию хостинг обеспечит сам.

Подведем итоги

Простота, гибкость, наличие огромного количества расширений и удобный шаблонизатор – главные преимущества Flask. При работе над проектом модуль FlatPages избавил нас и от необходимости подключения базы данных, и от написания скрипта для конвертации Markdown-файлов в html. Модуль Frozen Flask обеспечил автоматический экспорт статической копии сайта без ущерба для функциональности. Реализация этих операций на каком-либо другом фреймворке потребовала бы куда больше кода и усилий. Напоминаем, что весь код проекта находится здесь, а готовый сайт доступен на GitHub Pages.

***

Материалы по теме

20
Июн
2022

📰 Weekly #5: новости, подкасты, отборные статьи и обучающие материалы по фронтенду

В этом выпуске: собеседование на позицию Junior фронтенд-разработчика, как фронтенд-разработчикам и дизайнерам найти общий язык, HTTP/3 был представлен в виде стандарта RFC 9114, обзор RedwoodJS за 100 секунд и еще четыре десятка полезных ссылок и новостей.

Новости

React

Angular

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека фронтендера»

JavaScript, CSS и HTML


  • И действительно, в мире веб-разработки фреймворки приходят и уходят, но какой веб-сайт не возьми, там почти наверняка будет использоваться CSS. Что это за технология, которая с нами уже так долго, рассказывает София Валитова:

TypeScript

NodeJS

  • Виктор Хомяков из Яндекса рассказывает о видах проблем с памятью в браузерах и в Node.js, об ограничениях, которые часто упускаются из виду, и их преодолении.
  • TekTok Podcast #1: Тимур Шемсединов, однопоточный NodeJS:

Разное

***

Предыдущие выпуски

20
Июн
2022

🐍🥤 Flask за час. Часть 1: создаем адаптивный сайт для GitHub Pages

Изучаем основные принципы работы фреймворка, разрабатывая личный сайт с резюме, портфолио, блогом и контактной формой.

Flask – микрофреймворк: это означает, что в стандартную поставку входит только самое необходимое, а все остальное при необходимости легко подключается. Поэтому приставка «микро» не должна вводить в заблуждение – при желании на Flask можно реализовать серьезный, масштабируемый проект. А для реализации таких небольших веб-приложений, как наш сайт, Flask подходит как нельзя лучше.

Обзор проекта

Готовый сайт находится здесь. У сайта несколько секций:

  • Главная
  • Резюме
  • Портфолио
  • Блог
  • Контакты

Переключение между секциями создает иллюзию многостраничности, но в «живой» версии сайт – одностраничный. Бэкенд включает в себя модуль Frozen Flask, который превращает приложение в генератор статических сайтов (SSG): все страницы, необходимые для адекватного представления сайта в статической версии, создаются автоматически.

Готовый сайт на GitHub Pages
Готовый сайт на 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:

        Click==7.0
Flask==1.1.1
Flask-FlatPages==0.7.1
Frozen-Flask==0.15
itsdangerous==1.1.0
Jinja2==2.10.3
Markdown==3.1.1
MarkupSafe==1.1.1
Pygments==2.4.2
PyYAML==5.1.2
Werkzeug==0.16.0

    

Поместите файл в директорию проекта и выполните команду:

        pipenv install -r requirements.txt
    

Для быстрого знакомства с принципами работы Flask мы сначала создадим тестовый блог, а затем перейдем к реализации нашего проекта.

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека питониста»

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

Начнем с создания структуры проекта:

        ├── mysite.py
├── content
│   └── posts
│   	
├── static
└── templates

    

В папке 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:

        {% block content %}
<h2>Блог - тестовый запуск</h2>
            {% for post in posts %}
        	<small>{{ post.date }}</small>
        	<p>
          	<h3>
            	{{ post.title }}
          	</h3>
        	<p>
          	<i>{{ post.description }}</i>
        	</p>
         	<p>{{ post.html[:100]|safe }}</p>
            	<a href="{{ url_for('post', name=post.path.replace('posts/', '')) }}"><span>Читать</span></a>
        	</p>
        	{% endfor %}
{% endblock %}

    

А это шаблон для вывода записи на отдельной странице post.html:

        {{ post.date }}
{{ post.title }}
{{ post.dеscription }}
{{ post.html|safe }}

    

Оба шаблона мы доработаем на следующем этапе, а пока запустим приложение 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, в свою очередь, эти переменные можно вставить в нужные теги:

        <title>{{ title }}</title>
  <meta content="{{ description }}" name="description">
  <meta content="{{ keywords }}" name="keywords">

    

Если же переменных очень много, имеет смысл вынести словарь в отдельный файл – в дальнейшем мы воспользуемся именно этим вариантом.

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)

    

Сохраните этот код в templates/base.html:

        <!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <meta content="width=device-width, initial-scale=1.0" name="viewport">
  <title>{{ site_title }}</title>
  <meta content="{{ description }}" name="description">
  <meta content="{{ keywords }}" name="keywords">
  <link href="{{ url_for('static', filename='img/favicon.png') }}" rel="icon">
  <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i|Raleway:300,300i,400,400i,500,500i,600,600i,700,700i|Poppins:300,300i,400,400i,500,500i,600,600i,700,700i" rel="stylesheet">
  <link href="{{ url_for('static', filename='assets/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
  <link href="{{ url_for('static', filename='assets/bootstrap-icons/bootstrap-icons.css') }}" rel="stylesheet">
  <link href="{{ url_for('static', filename='assets/boxicons/css/boxicons.min.css') }}" rel="stylesheet">
  <link href="{{ url_for('static', filename='assets/glightbox/css/glightbox.min.css') }}" rel="stylesheet">
  <link href="{{ url_for('static', filename='assets/remixicon/remixicon.css') }}" rel="stylesheet">
  <link href="{{ url_for('static', filename='assets/swiper/swiper-bundle.min.css') }}" rel="stylesheet">
  <script src="https://kit.fontawesome.com/69e2443572.js" crossorigin="anonymous"></script>
  <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet">
</head>
<body>
  <main id="main">
{% block content %} <!-- вложенные шаблоны -->
{% endblock %}
  </main>
  <!-- Скрипты -->
  <script src="{{ url_for('static', filename='assets/purecounter/purecounter.js') }}"></script>
  <script src="{{ url_for('static', filename='assets/bootstrap/js/bootstrap.bundle.min.js') }}"></script>
  <script src="{{ url_for('static', filename='assets/glightbox/js/glightbox.min.js') }}"></script>
  <script src="{{ url_for('static', filename='assets/isotope-layout/isotope.pkgd.min.js') }}"></script>
  <script src="{{ url_for('static', filename='assets/swiper/swiper-bundle.min.js') }}"></script>
  <script src="{{ url_for('static', filename='assets/waypoints/noframework.waypoints.js') }}"></script>
  <script src="{{ url_for('static', filename='js/main.js') }}"></script>
</body>
</html>

    

А этот – в templates/index.html:

        {% extends "base.html" %}
{% block content %}
<h1>Здесь будет сайт</h1>
{% endblock %}

    

Сохраните в папке static все эти ассеты. Теперь можно запускать сервер python mysite.py– скелет сайта готов:

Значения тегов title, description и keywords взяты из файла settings.txt
Значения тегов title, description и keywords взяты из файла settings.txt

Перейдем к созданию первого шаблона, расширяющего index.htmlheader.html. Добавьте переменные в файл settings.txt:

        "site_url":"http://localhost:8000",
"tag1":"Разработчик и автор",
"tag2":"курсов по Django",
"sect1":"Главная",
"sect2":"Резюме",
"sect3":"Портфолио",
"sect4":"Блог",
"sect5":"Контакты",
"telegram":"https://t.me/johndoe",
"facebook":"ttps://facebook.com/john.doe",
"vk":"https://vk.com/john_doe",
"email":"mailto:[email protected]"

    

И отредактируйте файл index.html – теперь он будет включать в себя header.html с помощью include:

        {% extends "base.html" %}
{% block content %}
{% block header %}
{% include "header.html" %}
{% endblock %}
{% endblock %}

    

Перезагрузите страницу:

Хэдер включен в index.html
Хэдер включен в index.html

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

***

Материалы по теме

19
Июн
2022

Прибавление числа из html к числу из JS

Всем привет, нужна помощь. Я делаю pomodoro timer и у меня возникла проблема в прибавлении числа из html к числу из js. В общем, когда я нажимаю на кнопу, число должно прибавляться на 1, но оно не меняется.
Вот код html:
“`
<!DOCTYPE h…

19
Июн
2022

Прибавление числа из html к числу из JS

Всем привет, нужна помощь. Я делаю pomodoro timer и у меня возникла проблема в прибавлении числа из html к числу из js. В общем, когда я нажимаю на кнопу, число должно прибавляться на 1, но оно не меняется.
Вот код html:
“`
<!DOCTYPE h…

16
Июн
2022

Не получается отобразить картинку .png в приложении tkinter [дубликат]

Имеется программа 350x500px и кнопка 30x5px, в которую пытаюсь впихнуть картинку. Но вместо картинки отображается белый прямоугольник и при чём не важно, в кнопке это изображение или нет, большая картинка или нет, просто белый прямоугольни…

10
Июн
2022

🐍🚀 Django с нуля. Часть 3: создание профилей, сжатие изображений, CRUD и пагинация

В заключительной части туториала разберемся с автоматическим созданием профилей и уменьшением аватарок, реализуем CRUD, импортируем контент из json-файла и сделаем пагинацию.

Третий этап разработки

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

Сохранение изображений профилей

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

Чтобы изменить расположение папки, откройте my_site\settings.py и добавьте в начало файла import os, а в конец вставьте:

        MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

    

Запустите сервер, войдите в панель управления – там уже есть раздел Profiles, причем количество профилей равно 0, хотя мы создали нескольких пользователей. Чуть позже мы рассмотрим, как автоматически создавать профили одновременно с регистрацией аккаунтов, а пока что создадим вручную один профиль для админа с аватаркой, и один профиль для пользователя без аватарки – вернее, у него будет аватарка по умолчанию default.jpg, которую вам нужно будет создать и поместить в папку media (но не внутрь profile_pics, а рядом).

Внесите изменения в шаблон профиля users\profile.html:

        {% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
	<div class="content-section">
  	<div class="media">
    	<img class="rounded-circle account-img" src="{{ user.profile.image.url }}">
    	<div class="media-body">
      	<h2 class="account-heading">{{ user.username }}</h2>
  	    <p class="text-secondary">{{ user.email }}</p>
    	</div>
  	</div>
  	<!-- Здесь будет форма -->
	</div>
{% endblock content %}

    

Теперь профиль админа выглядит так:

В профиле админа появилась аватарка
В профиле админа появилась аватарка

Автоматическое создание профилей

Осталось решить задачу с автоматическим созданием профилей во время регистрации. В Джанго для реализации такой логики существуют сигналы. Создайте файл 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']

    

Перейдем к users\views.py – теперь он должен выглядеть так. В шаблон profile.html тоже нужно внести дополнения – вставьте этот код вместо комментария “здесь будет форма”:

           	<form method="POST" enctype="multipart/form-data">
      	{% csrf_token %}
      	<fieldset class="form-group">
          	<legend class="border-bottom mb-4">Ваш профиль</legend>
          	{{ u_form|crispy }}
              {{ p_form|crispy }}
      	</fieldset>
      	<div class="form-group">
          	<button class="btn btn-outline-info" type="submit">Обновить</button>
      	</div>
  	</form>
    

Теперь пользователи могут изменять информацию в своих профилях:

Пользователи могут самостоятельно изменить ник, емейл и аватар
Пользователи могут самостоятельно изменить ник, емейл и аватар

Автоматическое сжатие изображений

Если пользователи будут загружать слишком большие изображения, сервер скоро окажется перегруженным. Поэтому имеет смысл реализовать автоматическое сжатие изображений, используемых в качестве аватарок. Такую возможность предоставляет библиотека 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:

        <h2><a class="article-title" href="{% url 'post-detail' post.id %}">{{ post.title }}</a></h2>
    

Перейдем к шаблону создания новых постов. Создайте файл post_form.html с таким кодом. Форма будет отображаться по адресу http://localhost:8000/post/new/:

Пользователи могут создавать новые записи
Пользователи могут создавать новые записи

После создания записи следует перенаправить пользователя на отдельную страницу поста. Для этого измените существующий код 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 постов на странице
Пагинатор разделяет записи по 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')

    

Сделаем шаблон user_posts.html и добавим новый путь в файле blog\urls.py:

        path('user/<str:username>', UserPostListView.as_view(), name='user-posts').
    

Осталось внести поправку в данные автора в шаблон home.html:

        <a class="mr-2" href="{% url 'user-posts' post.author.username %}">{{ post.author }}</a>
    

и в post_detail.html:

        <a class="mr-2" href="{% url 'user-posts' object.author.username %}">{{ object.author }}</a>.
    

И все заработало:

Записи пользователя выводятся на его личной странице
Записи пользователя выводятся на его личной странице

Весь код для четвертого этапа можно взять здесь.

Заключение

Поэтапное создание простого веб-приложения дает возможность быстро освоить основные принципы разработки в Django. Фреймворк позволяет достаточно просто реализовать сложную функциональность – например, CRUD, а соответствующие библиотеки помогают разрабатывать формы и автоматически сжимать изображения. Напоминаем, что код для всех этапов проекта доступен здесь.

***

Материалы по теме

08
Июн
2022

🐍🚀 Django с нуля. Часть 2: регистрация, авторизация, ограничение доступа

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

Второй этап разработки

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

Создание учетных записей и администрирование

Панель администрирования открывается по адресу 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)

    

Теперь можно открыть админку http://localhost:8000/admin/ и создать несколько постов от разных пользователей:

Записи от нескольких пользователей
Записи от нескольких пользователей

Обратите внимание на формат даты – если указание часов и минут не требуется, формат можно изменить в шаблоне home.html:

        <small class="text-muted">{{ post.date_posted|date:"F d, Y" }}</small>
    
Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека питониста»

Формы регистрации и авторизации

Как уже упоминалось, приложения из проекта можно использовать отдельно – вставить блог, например, в другой проект. Поэтому и систему регистрации / авторизации стоит реализовать отдельно. Запустим Джанго-команду для создания нового приложения под названием users: python manage.py startapp users. После этого нужно зарегистрировать новое приложение, как мы уже делали с блогом. Сначала откройте my_site\settings.py и добавьте нужную строку в список INSTALLED_APPS:

        INSTALLED_APPS = [
	'blog.apps.BlogConfig',
	'users.apps.UsersConfig',
	'crispy_forms',
	'django.contrib.admin',
	'django.contrib.auth',
	'django.contrib.contenttypes',
	'django.contrib.sessions',
	'django.contrib.messages',
	'django.contrib.staticfiles',
]

    

В этом же файле в самом низу добавьте ссылку на стили 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 %}

    

Запустим python manage.py runserver и оценим нашу форму регистрации http://localhost:8000/register/:

Форма регистрации
Форма регистрации

Зарегистрируем нового пользователя NewUser и получим сообщение об успешной регистрации аккаунта. Проверим панель администрирования http://localhost:8000/admin/auth/user/ – новая учетная запись там появилась, значит, форма работает правильно. Попробуйте ввести некорректные регистрационные данные – форма проводит валидацию самостоятельно, без всяких дополнительных усилий с нашей стороны:

Форма неплохо справляется с валидацией
Форма неплохо справляется с валидацией

Вход и доступ к профилям для зарегистрированных пользователей

Одно из главных преимуществ системы авторизации – возможность показывать определенный контент только зарегистрированным пользователям. Сначала мы создадим логику и страницы входа и выхода, а затем перейдем к вопросу ограничения доступа для неавторизованных и/или незарегистрированных пользователей.

Прежде всего добавим в файл my_site\urls.py импорт нужных модулей и маршруты к шаблонам страниц входа и выхода. Теперь нужно создать два шаблона в папке users. Сохраните этот код для login.html. Он генерирует такую страницу:

Страница входа
Страница входа

Код для logout.html генерирует страницу выхода из учетной записи:

Страница выхода
Страница выхода

Внизу файла my_site\settings.py добавьте:

        LOGIN_REDIRECT_URL = 'blog-home'
LOGIN_URL = 'login'

    

Также отредактируем код в файле users\views.py, теперь он должен выглядеть так.

Сообщение об успешной регистрации
Сообщение об успешной регистрации

Чтобы управлять профилями в админ-панели, нужно зарегистрировать модель в 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. Создайте и примените миграции:

        python manage.py makemigrations 
python manage.py migrate

    

Теперь можно запускать сервер – у нас уже есть работающие страницы http://localhost:8000/login/ и http://localhost:8000/logout/; на страницу login выполняется переадресация после регистрации. Если сейчас ввести некорректный логин, появится сообщение об ошибке. Но и ввод верных данных приведет к ошибке 404 – приложение пытается открыть профиль пользователя, но у него пока что нет правильного маршрута к странице. На самом деле, и переадресация на профиль после входа на сайт выглядит странно – гораздо логичнее перенаправить пользователя на главную страницу блога, что мы и сделаем.

Займемся переадресацией откроем my_site\settings.py и добавим переадресацию в конце файла:

        LOGIN_URL = 'login'
    

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

Прежде всего, внесем изменения в шаблон base.html – найдите правый блок навигации и вставьте этот код между тегами <div class="navbar-nav"></div>:

                  	{% if user.is_authenticated %}
            	<a class="nav-item nav-link" href="{% url 'profile' %}">Профиль</a>
            	<a class="nav-item nav-link" href="{% url 'logout' %}">Выход</a>
          	{% else %}
            	<a class="nav-item nav-link" href="{% url 'login' %}">Вход</a>
            	<a class="nav-item nav-link" href="{% url 'register' %}">Регистрация</a>
          	{% endif %}
    

Если зайти на сайт с правильным логином и паролем, можно увидеть свой профиль – правда, пока без аватарки:

Профиль без изображения пользователя
Профиль без изображения пользователя

Последнее, что мы сделаем на этом этапе – обеспечим ограничение доступа к профилям для незарегистрированных пользователей. Для этого в файл users\views.py нужно добавить декоратор @login_required:

        @login_required
def profile(request):
	return render(request, 'users/profile.html')

    

Если неавторизованный пользователь теперь попытается открыть страницу профиля, он будет переадресован на страницу входа на сайт. Напоминаем: весь код, созданный на этом этапе работы, находится здесь.

Промежуточные итоги

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

***

Материалы по теме

06
Июн
2022

📰 Weekly #3: новости, подкасты, отборные статьи и обучающие материалы по фронтенду

Обзор нововведений Angular 14, подборка игровых площадок для изучения веб-разработки, 7 полезных расширений VS Code для React-разработчика, анонс самого большого обновления Next.js, лучшие практики по работе с Node.js и многое другое.

📰 Новости

🚀 Подборка игровых площадок для изучения веб-разработки:

  1. CSS Diner
  2. Codingame
  3. Screeps
  4. Flex-box Defense
  5. Untrusted
  6. Dungeons & Developers
  7. Elevator-Saga
  8. Code Wars
  9. CheckiO
  10. Pixactly
Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека фронтендера»

Angular

  • Обзор нововведений Angular 14.
  • Видеообзор Angular 14:

React

Vue

  • Vue 3: обзор различных вариантов взаимодействия компонентов.
  • Книга Fullstack Vue (2018), Автор: Hassan Djirdeh

Цель этой книги – стать единственным наиболее полезным ресурсом по обучению Vue.js . К тому времени, когда вы закончите читать эту книгу, у вас будет все необходимое для создания надежных, мощных приложений на Vue.

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

Next.js

  • Анонс самого большого обновления Next.js с момента его появления в 2016 году. Часть 1: обзор новой системы маршрутизации и ее интеграции с компонентами React Server и сбором данных.

JavaScript, CSS и HTML

  • Подборка малоизвестных и малоиспользуемых функций CSS в 2022 году, которая составлена с учетом мнения сообщества и личного взгляда автора статьи.
  • Современная отзывчивая типографика с использованием CSS clamp: полный гайд от теории к практике. En и Ру.
  • for-of vs. .reduce() vs. .flatMap(): сравнение трёх способов обработки массивов в JavaScript, которое поможет выбрать наиболее подходящий вариант для вашей работы.
  • Слайдер, который выглядит одинаково во всех браузерах: разбираем псевдоэлементы и префиксы свойств, на которые следует ориентироваться.
  • Коллекция сниппетов на JavaScript и CSS для ежедневных потребностей фронтенд-разработчика.
  • Оптимизация сборки JavaScript с помощью Metro: кейс Airbnb.
  • 🗓️ JavaScript и HTML: делаем простой календарь за 5 минут


  • Книга Html, Css & Javascript in easy steps Special Edition (2020), Автор: Mike McGrath.
Css &amp; Javascript in easy steps Special Edition (2020), Mike McGrath
Css & Javascript in easy steps Special Edition (2020), Mike McGrath

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

✔️ Теги языка разметки гипертекста (HTML)

✔️ Правила каскадных таблиц стилей (CSS)

✔️ Функции JavaScript

TypeScript

NodeJS

  • Лучшие практики по работе с Node.js в одном репозитории.
  • Руководство по использованию Vanilla JS + Twilio + Node.js для разработки группового чата.
  • Собеседование на middle Node.js разработчика:
  • Разработка на Node.js в 2022: тренды и приёмы:

Разное

Интервью

  • Интервью с преподавателем, программистом, open-source-разработчиком, node-контрибьютером — Тимуром Шемсединовым!
***

Материалы по теме

06
Июн
2022

🐍🚀 Django с нуля. Часть 1: пишем многопользовательский блог для клуба любителей задач Python

Собираетесь изучать Django, но не знаете, с чего начать? Расскажем, как быстро создать функциональное приложение, которое продемонстрирует базовые возможности фреймворка.

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

Обзор проекта

Мы создадим многопользовательский блог для клуба любителей задач Python Bytes. Вместе со стандартным пакетом Django будем использовать модули django-crispy-forms и Pillow. Реализуем всю функциональность, необходимую для:

  • регистрации и авторизации участников;
  • автоматического создания пользовательских профилей;
  • заполнения и изменения информации в профилях;
  • автоматического сжатия изображений для аватарок;
  • создания, редактирования и удаления записей со стороны фронтенда;
  • пагинации и вывода записей на страницах авторов.
Готовое приложение
Готовое приложение

Установка Django

Установим Django в виртуальное окружение с помощью менеджера pipenv:

        C:\Users\User>d:
D:\>mkdir Django
D:\>cd django
D:\>mkdir .venv
D:\django>pipenv install django

    

Размер пакета – чуть менее 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 успешно установлен
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, как показано ниже:

        INSTALLED_APPS = [
	'blog.apps.BlogConfig',
	'django.contrib.admin',
	'django.contrib.auth',
	'django.contrib.contenttypes',
	'django.contrib.sessions',
	'django.contrib.messages',
	'django.contrib.staticfiles',
]

    

Откройте 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. Напоминаем, что весь код для этого этапа можно взять здесь.

Вывод тестового контента
Вывод тестового контента

Подведем промежуточные итоги

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

***

Материалы по теме

26
Май
2022

Разработка на JavaScript с нуля в 2022 году: дорожная карта

Чтобы программирование на JavaScript было быстрым и эффективным с нуля, воспользуйтесь нашей дорожной картой.
— Читать дальше «Разработка на JavaScript с нуля в 2022 году: дорожная карта»

26
Май
2022

Как лучше реализовать 403 ошибку?

Всем привет, работаю на стеке React + Next.js и встал вопрос, как лучше реализовать 403 ошибку на фронте.
То есть:

Сделать в папке /pages у Next роут 403, чтобы происходил редирект на этот урл /403 и рисовался какой-то текст ошибки

Или с…

25
Май
2022

Не подгружается верстка, проблемы с маршрутизацией, все перелопатил – не смог найти проблемы

В общем, имеем вот такую страницу:
import React from ‘react’;

const Shop = () => {
return (
<div>
SHOP
</div>
);
};

export default Shop;

хочется увидеть ее вывод, для этого в файл приложения импортировал…

24
Май
2022

📰 Weekly #1: новости, подкасты, отборные статьи и обучающие материалы по фронтенду

Первый выпуск посвящен фронтенду: шпаргалка по основным концепциям React, реализация шагающей игрушки слинки на чистом CSS, руководство по TypeScript для начинающих, интервью «Как инженеру не умереть со скуки во фронтенде» и еще четыре десятка полезных ссылок.

Новости

React

  • Шпаргалка по основным концепциям React.
  • Разработка простого клона Twitter с функциями CRUD для публикации, чтения и удаления твитов.
  • Batching, useDeferredValue, useTransition и другие новые фичи React 18 в обзоре Ulbi TV:
Обзор React 18
  • Разбор практических шагов, которые помогут повысить производительность при использовании Next.js.
  • В этом ролике ты разработаешь свои шахматы на 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
Учебник The React beginners handbook — Flavio Copes

В книге описываются основы React JS:

  • Почему Реакт стал популярным.
  • Как установить реакт.
  • Классовые и функциональные компоненты.
  • Состояние компонентов.
  • Props.
  • Жизненный цикл компонентов.

JavaScript, CSS и HTML

  • Курс, посвящённый основам JavaScript, CSS и HTML от специалистов Azure Cloud Advocates из Microsoft включает 24 урока и рассчитан на 12 недель (некоторые уроки переведены на русский). Каждый урок содержит тесты до и после урока, задание, решение, письменные инструкции по завершении урока и многое другое (GitHub, GitHub Pages).
  • quick-lint-js — линтер для JavaScript-кода, который быстрее, проще и дружелюбнее ESLint.
  • Реализация шагающей игрушки слинки на чистом CSS. Интересные подходы и приемы CSS-анимации в пошаговом руководстве.
  • 6 кейсов HTML и CSS, которые многие разработчики упускают из виду.

Полифилы на JavaScript: простое и понятное объяснение от Елены Литвиновой

TypeScript

NodeJS

  • sdc-check — легковесный инструмент для выявления рисков в ваших npm-зависимостях и обеспечения превентивных мер защиты.

Разное


Интервью

🎙 Как инженеру не умереть со скуки во фронтенде

Запись подкаста Frontend Weekend с Полиной Гуртовой