🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Покажем, как писать маршруты и функции представления, использовать шаблоны и работать с базами данных. В конце статьи – 10 мини-проектов, от модулей инвентаризации и учета товаров до приложения для хранения заметок и блога.
🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Flask – компактный фреймворк для быстрой разработки веб-приложений. Он предоставляет минимальную необходимую функциональность и не навязывает никаких строгих правил в отношении структуры и архитектуры приложения (как это делает Django).

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

Основные преимущества Flask:

  • Минималистичность. Flask отличается небольшим размером – в нем есть все самое необходимое и нет ничего лишнего.
  • Гибкость. Фреймворк не диктует определенных правил и позволяет разработчику сохранить полный контроль над структурой приложения.
  • Простота в использовании. Он имеет несколько встроенных функций, которые позволяют сразу начать создавать полноценные веб-приложения, даже если у вас нет опыта в веб-разработке на Python. Например, у Flask есть встроенный сервер, поддержка сессий, обработчик форм, шаблонизатор.
  • Интеграция с дополнительными библиотеками. Фреймворк очень просто интегрируется с многочисленными библиотеками, которые расширяют его функциональность. Это позволяет создать гибкий, масштабируемый проект для любой сферы.
  • Простота тестирования. У Flask есть встроенный тестовый клиент, который максимально упрощает тестирование и отладку.

Установка

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

        python -m venv fproject\venv
    

Перейдите в только что созданную директорию:

        cd fproject
    

Активируйте окружение:

        venv\scripts\activate
    

И установите Flask:

        pip install flask
    

Активировать виртуальное окружение нужно перед каждым сеансом работы с Flask.

🐍🎓 Библиотека собеса по Python
Подтянуть свои знания по Python вы можете на нашем телеграм-канале «Библиотека собеса по Python»
🐍🧩 Библиотека задач по Python
Интересные задачи по Python для практики можно найти на нашем телеграм-канале «Библиотека задач по Python»

Простейшее приложение на Flask

Напишем приложение, которое будет выводить традиционное приветствие Hello, World! в браузере. Сохраните этот код в файле app.py в директории fproject:

        from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello, World!'

if __name__ == '__main__':
    app.run()

    

Этот код создает объект приложения Flask с помощью класса Flask и присваивает его переменной app. Декоратор @app.route('/') устанавливает маршрут для главной страницы нашего приложения, а метод def hello() определяет, что будет отображаться на этой странице.

if __name__ == '__main__': проверяет, запускается ли данный файл как самостоятельное приложение, или импортируется как модуль. В нашем случае он запускается как независимое приложение, поэтому вызывается метод app.run(), который запускает веб-сервер Flask.

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

        (venv) C:\Users\User\fproject>app.py

    

Откройте адрес http://localhost:5000/ в браузере:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Flask по умолчанию использует порт 5000. При желании его можно изменить на более привычный 8000:

        app.run(port=8000)
    

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

        app.run(debug=True)
    

Для остановки сервера нажмите Ctrl+C.

Маршруты в Flask

Маршруты – это URL-адреса, по которым пользователи могут открывать определенные страницы (разделы) веб-приложения. Маршруты в Flask определяются с помощью декоратора @app.route(). Для каждого маршрута можно написать отдельную функцию представления, которая будет выполнять какие-то действия при переходе по определенному адресу. Рассмотрим пример:

        from flask import Flask

app = Flask(__name__)

@app.route('/')
def home():
    return 'Это главная страница.'

@app.route('/about')
def about():
    return 'Здесь будет информация об авторе сайта.'

@app.route('/blog')
def blog():
    return 'Это блог с заметками о работе и увлечениях.'

if __name__ == '__main__':
    app.run()

    

Сохраните код, запустите приложение, последовательно откройте адреса:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Переменные в маршрутах

В URL можно передавать различные значения. Запустите этот код и перейдите по адресу, например, http://localhost:5000/user/EvilAdmin

        from flask import Flask

app = Flask(__name__)

@app.route('/user/<username>')
def user_profile(username):
    return f"Это профиль пользователя {username}"

if __name__ == '__main__':
    app.run()

    

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

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

А так можно передать в маршруте целое число:

        from flask import Flask

app = Flask(__name__)

@app.route('/user/<int:user_id>')
def user_profile(user_id):
    return f"Это профиль пользователя с ID {user_id}"

if __name__ == '__main__':
    app.run()

    

Перейдите по адресу, например, http://localhost:5000/user/5:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

GET- и POST-запросы

GET и POST – это HTTP-запросы, которые используются для отправки данных между клиентом и сервером.

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

POST-запрос используют для отправки данных на сервер. При выполнении POST-запроса клиент отправляет данные на сервер, а сервер их обрабатывает. POST-запросы обычно применяют для отправки форм, с данными из которых нужно что-то сделать на бэкенде.

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

        from flask import Flask, request, render_template

app = Flask(__name__)

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        # проверка логина и пароля
        return 'Вы вошли в систему!'
    else:
        return render_template('login.html')

if __name__ == '__main__':
    app.run()

    

Маршрут @app.route('/login', methods=['GET', 'POST']) обрабатывает и POST, и GET-запросы: в первом случае он отправит данные на сервер, во втором – просто выведет страницу с формой авторизации.

Для вывода формы на странице сделаем простейший шаблон. Этот код нужно сохранить в файле login.html, в директории templates (в этой папке Flask по умолчанию ищет шаблоны):

        {% extends 'base.html' %}

{% block content %}
  <div class="container">
    <div class="row justify-content-center mt-5">
      <div class="col-md-6">
        <div class="card">
          <div class="card-header">
            <h1 class="text-center">Вход на сайт</h1>
          </div>
          <div class="card-body">
            {% with messages = get_flashed_messages() %}
              {% if messages %}
                <div class="alert alert-danger">
                  <ul>
                    {% for message in messages %}
                      <li>{{ message }}</li>
                    {% endfor %}
                  </ul>
                </div>
              {% endif %}
            {% endwith %}
            <form method="post">
              <div class="mb-3">
                <label for="username" class="form-label">Логин:</label>
                <input type="text" class="form-control" id="username" name="username" required>
              </div>
              <div class="mb-3">
                <label for="password" class="form-label">Пароль:</label>
                <input type="password" class="form-control" id="password" name="password" required>
              </div>
              <div class="text-center">
                <button type="submit" class="btn btn-primary">Войти</button>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
  </div>
{% endblock %}
    

Никакие CSS стили к шаблону не подключены, поэтому он выглядит не слишком привлекательно. Но шаблон работает, а форма получает логин и пароль:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Шаблонизатор Jinja2

Шаблоны в Flask используются для динамического формирования веб-страниц. Шаблоны представляют собой HTML страницы, в которые можно передавать любые данные с бэкенда. К шаблонам можно подключать любые CSS-фреймворки типа Bootstrap и Tailwind, и любые JS-скрипты.

Поведением шаблонов управляет шаблонизатор Jinja2 – он предоставляет функциональность для создания условий, циклов, макросов, наследования и блоков. Главные преимущества шаблонизатора:

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

Наследование работает так:

  • Базовый шаблон, который обычно называется base.html, содержит общую разметку для сайта.
  • В base.html подключаются локальные и CDN-фреймворки (CSS, JS), задаются фоновые изображения и фавикон.
  • Дочерние шаблоны наследуют этот базовый шаблон и дополняют его своим собственным контентом.

Продемонстрируем наследование на примере. Сохраните в папке templates два файла. Это содержимое файла base.html – в нем подключается CSS-фреймворк Bootstrap, кастомные стили custom.css из статической папки static, иконки Font Awesome:

        <!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>{% block title %}{% endblock %}</title>
    <!-- Bootstrap стили -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- иконки fontawesome -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
    <!-- кастомные стили -->
    <link rel="stylesheet" href="{{ url_for('static', filename='custom.css') }}">
</head>
<body>

<!-- навигация -->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container">
        <a class="navbar-brand" href="#">Мой личный сайт</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse"
                data-bs-target="#navbarNav" aria-controls="navbarNav"
                aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse justify-content-end"
             id="navbarNav">
            <ul class="navbar-nav">
                <li class="nav-item">
                    <a class="nav-link" href="#">Главная</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">Обо мне</a>
                </li>
            </ul>
        </div>
    </div>
</nav>

<!-- контент дочерних шаблонов -->
<div class="container my-3">
    {% block content %}
    {% endblock %}
</div>

</body>
</html>

    

Шаблон base.html также содержит верхнее меню для навигации по сайту – это меню будут наследовать все дочерние шаблоны. Вот пример дочернего шаблона about.html:

        {% extends 'base.html' %}

{% block title %}Мое резюме{% endblock %}

{% block content %}
    <div class="container my-5">
        <h1 class="text-center mb-4">Мое резюме</h1>
        <div class="row">
            <div class="col-md-6">
                <h2>Образование</h2>
                <h4>Московский политехнический институт</h4>
                <p class="mb-0">Бакалавр Computer Science</p>
                <p class="text-muted">2016 - 2020</p>
            </div>
            <div class="col-md-6">
                <h2>Опыт работы</h2>
                <h4>Web Developer - XYZ компания</h4>
                <p class="mb-0">2019 - н.в.</p>
                <p class="text-muted">- Разработка и поддержка веб-приложений</p>
                <p class="text-muted">- Работа с Python, Django, HTML/CSS, JavaScript, MySQL</p>
            </div>
        </div>
        <div class="row mt-5">
            <div class="col-md-6">
                <h2>Навыки</h2>
                <ul class="list-group">
                    <li class="list-group-item border-0 py-1"><i class="fa fa-cog"></i> Python</li>
                    <li class="list-group-item border-0 py-1"><i class="fa fa-cog"></i> Django</li>
                    <li class="list-group-item border-0 py-1"><i class="fa fa-cog"></i> HTML/CSS</li>
                    <li class="list-group-item border-0 py-1"><i class="fa fa-cog"></i> JavaScript</li>
                </ul>
            </div>
            <div class="col-md-6">
                <h2>Проекты</h2>
                <h4>Сайт для продажи автомобилей</h4>
                <p class="text-muted mb-0">- Разработка сайта с использованием Django</p>
                <p class="text-muted">- Интеграция с API маркетплейса для получения данных об автомобилях</p>
                <h4>Игровой блог</h4>
                <p class="text-muted mb-0">- Разработка блога с использованием Django</p>
                <p class="text-muted">- Возможность создавать учeтные записи пользователей и писать комментарии</p>
            </div>
        </div>
        <div class="row mt-5">
            <div class="col-md-6">
                <h2>Контакты</h2>
                <p class="mb-0"><i class="fa fa-phone"></i> Телефон: +990123456789</p>
                <p class="mb-0"><i class="fa fa-envelope"></i> Email: example@example.com</p>
                <p class="mb-0"><i class="fa fa-github"> GitHub: <a href="https://github.com/example"></i>example</a></p>
            </div>
            <div class="col-md-6">
                <h2>Языки</h2>
                <ul class="list-group">
                    <li class="list-group-item border-0 py-1"><i class="fa fa-check-circle"></i> Английский (C1)</li>
                    <li class="list-group-item border-0 py-1"><i class="fa fa-check-circle"></i> Немецкий (B2)</li>
                    <li class="list-group-item border-0 py-1"><i class="fa fa-check-circle"></i> Русский (родной)</li>
                </ul>
            </div>
        </div>
    </div>
{% endblock %}

    

Фон страницы шаблонизатор берет из файла static/customs.css:

        body {
    background-color: #e5e5e5;
}

    

А код для вывода страницы выглядит так:

        from flask import Flask, render_template

app = Flask(__name__)

@app.route('/about')
def about():
    return render_template('about.html')

if __name__ == '__main__':
    app.run(debug=True)

    

Запустите приложение, откройте адрес http://localhost:5000/about:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Работа с базой данных

Для работы с базами данных в Flask удобно использовать ORM SQLAlchemy. Как уже упоминалось в предыдущей главе о SQLite, ORM играет роль своеобразной прослойки между приложением и СУБД SQLite, и позволяет работать с базами без использования языка SQL. Надо заметить, что работать с базами данных в SQLAlchemy немного сложнее, чем в Django ORM, но гораздо проще, чем в чистом Python.

Начнем с установки SQLAlchemy в виртуальное окружение:

        pip install flask-sqlalchemy
    

В SQLAlchemy основой для создания таблиц в базе данных служат модели (специальные классы). Поля классов определяют структуру таблицы, которая будет использоваться для хранения информации в базе данных. В полях классов можно задавать типы данных, которые соответствуют типам данных в БД, например, String для хранения строк, Integer для целых чисел, Float для плавающих чисел и т.д.

SQLAlchemy, как и другие ORM, очень упрощает создание связей между таблицами. В приведенном ниже примере используется связь один ко многим (ForeignKey), поскольку у одного исполнителя может быть несколько альбомов, а в одном альбоме всегда будет несколько треков:

        from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Artist(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)

class Album(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False)
    year = db.Column(db.String(4), nullable=False)
    artist_id = db.Column(db.Integer, db.ForeignKey('artist.id'), nullable=False)
    artist = db.relationship('Artist', backref=db.backref('albums', lazy=True))

class Song(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False)
    length = db.Column(db.String(4), nullable=False)
    track_number = db.Column(db.Integer, nullable=False)
    album_id = db.Column(db.Integer, db.ForeignKey('album.id'), nullable=False)
    album = db.relationship('Album', backref=db.backref('songs', lazy=True))

    

Сохраните этот код в файле models.py – мы будем импортировать модели из него в главный файл приложения app.py и в скрипт create_db.py, который создает базу данных и заполняет ее тестовой информацией.

Код для create_db.py будет следующим:

        from flask import Flask
from models import Artist, Album, Song, db
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///music.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)


if __name__ == '__main__':
    with app.app_context():
        db.create_all()

        # создаем тестовых исполнителей
        artist1 = Artist(name='The Rolling Stones')
        artist2 = Artist(name='Jefferson Airplane')
        artist3 = Artist(name='Nine Inch Nails')
        artist4 = Artist(name='Tool')
        db.session.add_all([artist1, artist2, artist3, artist4])
        db.session.commit()

        # создаем тестовые альбомы
        album1 = Album(title='Aftermath', year='1966', artist=artist1)
        album2 = Album(title='Beggars Banquet', year='1968', artist=artist1)
        album3 = Album(title='Surrealistic Pillow', year='1967', artist=artist2)
        album4 = Album(title='Broken', year='1992', artist=artist3)
        album5 = Album(title='The Fragile', year='1999', artist=artist3)
        album6 = Album(title='Lateralus', year='2001', artist=artist4) 
        album7 = Album(title='AEnima', year='1996', artist=artist4) 
        album8 = Album(title='10,000 Days', year='2006', artist=artist4) 

        # создаем тестовые песни
        song1 = Song(title='Paint it Black', length='4:20', track_number=1, album=album1)
        song2 = Song(title='Sympathy For The Devil', length='3:53', track_number=2, album=album1)
        song3 = Song(title='White Rabbit', length='3:42', track_number=5, album=album3)
        song4 = Song(title='Wish', length='3:46', track_number=6, album=album4)
        song5 = Song(title='Starfuckers, Inc.', length='5:00', track_number=1, album=album5)
        song6 = Song(title='Schism', length='6:46', track_number=7, album=album6)
        song7 = Song(title='Eulogy', length='8:29', track_number=3, album=album7)
        song8 = Song(title='Vicarious', length='7:07', track_number=5, album=album8)
        db.session.add_all([album1, album2, album3, album4, album5, album6, album7, album8, song1, song2, song3, song4, song5, song6, song7, song8])
        db.session.commit()
    

Этот код наглядно демонстрирует, как именно создаются записи, и какие между ними существуют связи. Чтобы создать и заполнить базу, запустите файл в активированном виртуальном окружении:

        (venv) C:\Users\User\fproject>create_db.py
    

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

Главный файл приложения app.py выглядит так:

        from flask import Flask, render_template
from models import Artist, Album, Song, db

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///music.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# связываем приложение и экземпляр SQLAlchemy
db.init_app(app)


@app.route('/songs')
def songs():
    songs_list = Song.query.all()
    return render_template('songs.html', songs=songs_list)

if __name__ == '__main__':
    app.run(debug=True)
    

Шаблон songs.html использует тот же самый базовый base.html, что и предыдущий пример:

        {% extends 'base.html' %}

{% block title %}
Мои любимые песни
{% endblock %}

{% block content %}
<h1 class="mb-5">Мои любимые песни</h1>

<div class="card-columns">
  <div class="row">
  {% for song in songs %}
    <div class="col-md-3">
      <div class="card mb-3">
          <div class="card-header fw-bold">{{ song.title }}</div>
          <div class="card-body">
              <p class="badge bg-primary text-wrap">{{ song.album.artist.name }}</p>
              <p class="card-text">Альбом: 
              <strong>{{ song.album.title }}</strong></p>
              <p class="card-text">Длина: {{ song.length }} минут</p>
              <p class="card-text">Номер трека: {{ song.track_number }}</p>
              <p class="card-text">Дата релиза: {{ song.album.year }}</p>
          </div>
      </div>
    </div>
  {% endfor %}
  </div>
</div>

{% endblock %}

    

После создания шаблона можно запустить приложение:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Практика

Задание 1

Напишите Flask-приложение, которое выводит в шаблон index.html приветствие для пользователя. Приветствие зависит от времени суток:

  • С 6:00 до 12:00 – «Доброе утро»
  • С 12:00 до 18:00 – «Добрый день»
  • С 18:00 до 24:00 – «Добрый вечер»
  • С 00:00 до 6:00 – «Доброй ночи»

Пример:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Решение:

Код для app.py выглядит так:

        from flask import Flask, render_template
import datetime

app = Flask(__name__)

@app.route('/')
def index():
    now = datetime.datetime.now()
    if now.hour >= 6 and now.hour < 12:
        greeting = 'Доброе утро'
    elif now.hour >= 12 and now.hour < 18:
        greeting = 'Добрый день'
    elif now.hour >= 18 and now.hour < 24:
        greeting = 'Добрый вечер'
    else:
        greeting = 'Доброй ночи'
    return render_template('index.html', greeting=greeting)

if __name__ == '__main__':
    app.run(debug=True)

    

Для вывода приветствия используются шаблоны base.html и index.html.

Задание 2

Напишите Flask-приложение, которое с помощью шаблона выводит пронумерованный список дел.

Пример:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Решение:

Это код приложения app.py:

        from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def task_list():
    tasks = ["Выгулять собаку", "Погладить рубашку", "Зайти в супермаркет", 
    "Убрать на кухне", "Дописать статью", "Позвонить тимлиду"]
    return render_template('task_list.html', tasks=tasks)

if __name__ == '__main__':
    app.run()

    

Нумерацию в Jinja2 легко реализовать с помощью loop.index:

        <!DOCTYPE html>
<html>
  <head>
    <title>Мой список важных дел</title>
    <style>
      ul.no-bullets {
      list-style-type: none; 
      }
    </style>
  </head>
  <body>
    <h1>Список дел на сегодня:</h1>
    <ul class="no-bullets">
      {% for task in tasks %}
        <li>{{loop.index}}. {{ task }}</li>
      {% endfor %}
    </ul>
  </body>
</html>

    

Задание 3

Напишите app.py и шаблон welcome.html, которые выводят различный контент для пользователей с разными правами доступа:

  • Админ имеет полный доступ.
  • Модератор может редактировать записи и комментарии.
  • Рядовой пользователь может создавать записи от своего имени и просматривать френдленту.

Пример:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Решение:

В приложении app.py можно определить только маршрут, вся функциональность по определению уровней доступа находится в шаблоне:

        <!DOCTYPE html>
<html>
  <head>
    <title>Личный кабинет</title>
  </head>
  <body>
    {% if user_level == 'admin' %}
      <h1>Привет, админ!</h1>
      <p>У тебя есть доступ ко всем настройкам.</p>
      <a href="#">Редактирование профилей</a>
      <a href="#">Создание учетных записей</a>
      <a href="#">Публикация статей</a>
    {% elif user_level == 'moderator' %}
      <h1>Привет, модератор!</h1>
      <p>У тебе есть доступ к редактированию записей.</p>
      <a href="#">Редактирование записей</a>
      <a href="#">Модерация комментариев</a>
    {% else %}
      <h1>Привет, пользователь!</h1>
      <p>У тебя нет доступа к редактированию контента и настроек.</p>
      <a href="#">Новая запись</a>
      <a href="#">Записи друзей</a>      
    {% endif %}
  </body>
</html>

    

Задание 4

Напишите скрипт для создания и заполнения базы данных SQLite данными о книгах из файла books.json, а также app.py и шаблоны, которые выводят:

  • Карточки с информацией о книгах.
  • Карточку отдельной книги.

Пример:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Решение:

Напишем модель Book и скрипт, который создает и заполняет базу из json-файла. Затем создадим app.py с двумя маршрутами – для вывода всех книг, и для вывода отдельной книги:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Задание 5

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

  • Каждый производитель (Manufacturer) поставляет несколько типов товаров (Category) – ноутбуки, наушники, смартфоны и так далее.
  • Одну и ту же категорию товаров могут производить несколько компаний.
  • В каждой категории может быть множество товаров (Item).

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

Пример:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Решение:

Файл models.py, описывающий структуру базы данных, выглядит так:

        from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

manufacturer_items = db.Table('manufacturer_items',
    db.Column('manufacturer_id', db.Integer, db.ForeignKey('manufacturer.id'), primary_key=True),
    db.Column('item_id', db.Integer, db.ForeignKey('item.id'), primary_key=True)
)

class Manufacturer(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), nullable=False)
    items = db.relationship('Item', secondary=manufacturer_items, backref=db.backref('manufacturers', lazy=True))

    def __repr__(self):
        return '<Manufacturer %r>' % self.name

class Category(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), nullable=False)
    items = db.relationship('Item', backref='category')

    def __repr__(self):
        return '<Category %r>' % self.name

class Item(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), nullable=False)
    description = db.Column(db.String(255), nullable=False)
    price = db.Column(db.Float, nullable=False)
    quantity = db.Column(db.Integer, nullable=False, default=0)
    category_id = db.Column(db.Integer, db.ForeignKey('category.id'), nullable=False)

    def __repr__(self):
        return '<Item %r>' % self.

    

Для заполнения базы данными из файла info.csv напишем скрипт. Приложение использует 4 шаблона:

За вывод всех товаров определенного производителя в отдельной категории отвечает эта функция:

        @app.route('/<manufacturer>/<category>')
def show_items(manufacturer, category):
    items = Item.query.join(Item.manufacturers).join(Item.category).\
                filter(Manufacturer.name == manufacturer).\
                filter(Category.name == category).all()
    return render_template('items.html', manufacturer=manufacturer, category=category, items=items)

    
🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Задание 6

Для супермаркета нужно написать веб-приложение, которое выводит список товаров на складе и позволяет добавлять новые.

Пример:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Решение:

Приложение состоит из файлов app.py, create_db.py и models.py. Для добавления новых товаров используется шаблон add.html и маршрут/функция add:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Задание 7

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

Пример:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Решение:

Начнем с создания базы данных на основе моделей. Функции add_patient, edit_patient, delete_patient реализованы в приложении app.py. Шаблоны add.html и edit.html обеспечивают добавление и редактирование карточек:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Задание 8

Напишите модуль аутентификации для Flask-приложения. Необходимо реализовать:

  • регистрацию;
  • проверку учетных данных при входе;
  • перенаправление на страницу профиля.

Пример:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Решение:

Проект включает в себя файлы app.py, create_db.py и models.py. Кроме того, модуль использует шаблоны:

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

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Задание 9

Напишите веб-приложение для хранения заметок. Необходимо реализовать набор CRUD операций – вывод, добавление, редактирование и удаление заметок. При создании базы данных следует учесть, что заметка может относиться только к одной категории, а в категории может быть множество заметок. На главной странице выводятся все заметки, причем текст ограничивается первыми 300 символами. Нажатие на ссылку «Далее» открывает страницу с полным текстом заметки.

Пример:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Решение:

База данных для приложения создается с помощью скрипта create_db.py на основе моделей. CRUD операции описаны в app.py. При нажатии на название категории шаблон и маршрут category выводят все заметки, относящиеся к данной теме.

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Задание 10

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

Пример:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

Решение:

Прежде всего разработаем модели Tag, Category и Post, а затем создадим на их основе базу данных при помощи скрипта.

Приложение использует следующие шаблоны:

CRUD операции реализованы в главном файле приложения app.py. Чтобы самые свежие записи выводились первыми, в models.py мы определили метод newest_first. При нажатии на ссылку «Читать» выводится полный текст записи:

🐍 Самоучитель по Python для начинающих. Часть 23: Основы веб-разработки на Flask

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

Мы рассмотрели основные приемы разработки простых веб-приложений на основе фреймворка Flask:

  • Создание маршрутов и функций представления.
  • Получение и обработку данных с фронтенда.
  • CRUD операции.
  • Основные возможности шаблонизатора Jinja2.

При создании приложений Flask для получения данных с фронтенда обычно используются формы WTF Forms. В этой статье при решении заданий намеренно использовались HTML-формы – так процесс передачи и обработки данных выглядит максимально понятно.

В следующей статье будем изучать NumPy.

Содержание самоучителя

  1. Особенности, сферы применения, установка, онлайн IDE
  2. Все, что нужно для изучения Python с нуля – книги, сайты, каналы и курсы
  3. Типы данных: преобразование и базовые операции
  4. Методы работы со строками
  5. Методы работы со списками и списковыми включениями
  6. Методы работы со словарями и генераторами словарей
  7. Методы работы с кортежами
  8. Методы работы со множествами
  9. Особенности цикла for
  10. Условный цикл while
  11. Функции с позиционными и именованными аргументами
  12. Анонимные функции
  13. Рекурсивные функции
  14. Функции высшего порядка, замыкания и декораторы
  15. Методы работы с файлами и файловой системой
  16. Регулярные выражения
  17. Основы скрапинга и парсинга
  18. Основы ООП: инкапсуляция и наследование
  19. Основы ООП: абстракция и полиморфизм
  20. Графический интерфейс на Tkinter
  21. Основы разработки игр на Pygame
  22. Основы работы с SQLite
  23. Основы веб-разработки на Flask
  24. Основы работы с NumPy
  25. Основы анализа данных с Pandas
***

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

МЕРОПРИЯТИЯ

Комментарии

ВАКАНСИИ

Добавить вакансию
Java Team Lead
Москва, по итогам собеседования
Senior Java Developer
Москва, по итогам собеседования

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ