Эта статья — пошаговое руководство по настройке базового CRUD-приложения с помощью Vue и Flask. Начнём с создания нового приложения Vue, используя Vue CLI, а затем перейдём к выполнению основных операций CRUD с помощью RESTful API на бэкенде под управлением Python и Flask.
Результат:
Основные зависимости:
Vue v2.5.2,
Vue CLI v2.9.3,
Node v10.3.0,
npm v6.1.0,
Flask v1.0.2,
Python v3.6.5.
Цели
К концу этого урока вы узнаете:
что такое Flask;
что такое Vue и как он соотносится с другими UI-библиотеками и фронтенд-фреймворками вроде Angular и React.
И научитесь:
выстраивать Vue-проект, используя Vue CLI;
создавать и рендерить компоненты Vue в браузере;
создавать одностраничные приложения с компонентами Vue;
подключать Vue-приложение к бэкенду Flask;
разрабатывать RESTful API с помощью Flask;
стилизовать компоненты Vue с помощью Bootstrap;
использовать Vue Router для создания маршрутов и рендеринга компонентов.
Что такое Flask?
Flask — это простой, но мощный микро-фреймворк для Python, идеально подходящий для создания RESTful API. Как Sinatra (Ruby) и Express (Node), он минималистичен и гибок, поэтому вы можете начинать с простых проектов и при необходимости создавать более сложные приложения.
Если вы первый раз работаете с Flask, вам стоит изучить следующие ресурсы:
Vue — это JavaScript-фреймворк с открытым исходным кодом. Используется для создания пользовательских интерфейсов. Он содержит некоторые из лучших концепций React и Angular, но по сравнению с ними он более доступен, поэтому новички могут быстро приступать к работе. Также он не уступает этим фреймворкам в мощности и предоставляет все необходимые функции для создания современных фронтенд-приложений.
Чтобы узнать больше о Vue, а также о плюсах и минусах его использования по сравнению с Angular и React, можете посмотреть следующие статьи:
Добавьте файл app.py в только что созданный каталог:
from flask import Flask, jsonify
from flask_cors import CORS
# configuration
DEBUG = True
# instantiate the app
app = Flask(__name__)
app.config.from_object(__name__)
# enable CORS
CORS(app)
# sanity check route
@app.route('/ping', methods=['GET'])
def ping_pong():
return jsonify('pong!')
if __name__ == '__main__':
app.run()
Flask-CORS нужен для отправки cross-origin-запросов (запросы, исходящие из другого протокола, IP-адреса, имени домена или порта), поэтому необходимо включить общий доступ к ресурсам (CORS).
Стоит отметить, что описанная выше настройка позволяет отправлять запросы из разных источников по всем маршрутам из любого домена, протокола или порта. В продакшне должны быть разрешены только запросы из домена, на котором размещено фронтенд-приложение. Для получения дополнительной информации можете ознакомиться с документацией Flask-CORS.
Запустим приложение:
(env)$ python app.py
Для проверки введите в строку адреса браузера http://localhost:5000/ping. Должно получиться: «Pong!».
Нажмите Ctrl + C, чтобы завершить работу сервера. Затем вернитесь к корневой папке проекта. Теперь перейдём к фронтенду и настроим Vue.
Настройка Vue
Для создания индивидуального темплейта проекта используем мощный интерфейс Vue CLI.
Установите его глобально:
$ npm install -g vue-cli@2.9.3
Если вы первый раз работаете с npm, вам будет полезно почитать официальное руководство по нему.
В каталоге flask-vue-crud выполните следующую команду для инициализации нового проекта Vue под именем client с конфигом webpack:
$ vue init webpack client
webpack — это пакетный модуль и инструмент для сборки, используемый для создания, минимизации и объединения файлов JavaScript и других клиентских ресурсов.
Шаги создания нового проекта Vue:
Vue-сборка: Runtime + Compiler.
Установить vue-router? — Да.
Использовать ESLint для линтинга кода? — Да.
Выберите пресет ESLint — Airbnb.
Настроить юнит-тесты? — Нет.
Настроить тесты e2e с Nightwatch? — Нет.
Запустить установку npm после создания проекта? — Да, использовать NPM.
Должно получиться следующее:
? Имя проекта client
? Описание проекта Vue.js
? Автор Michael Herman michael@mherman.org
? Автономная сборка Vue
? Установить vue-router? — Да
? Использовать ESLint для линтинга кода? — Да
? Выберите пресет ESLint — Airbnb
? Настроить юнит-тесты? — Нет
? Настроить тесты e2e с Nightwatch? — Нет
? Запустить установку npm после создания проекта? (рекомендуется) — npm
Обратите внимание на сгенерированную структуру проекта. Она может показаться большой, но по факту вы будете иметь дело только с файлами и папками в каталоге /src вместе с файлом index.html.
Файл index.html является отправной точкой данного Vue-приложения.
Также обратите внимание на элемент <div> с идентификатором app. Это контейнер, который Vue будет использовать для присоединения сгенерированных HTML и CSS при создании пользовательского интерфейса.
main.js — точка входа в приложение, которая загружает и инициализирует Vue вместе с корневым компонентом. App.vue — корневой компонент, из которого будут рендериться все остальные компоненты (отправная точка). assets — место хранения статических ассетов вроде изображений и шрифтов. components — место хранения UI-компонентов. router — место определения URL-адресов и сопоставление их с компонентами.
Взгляните на файл client/src/components/HelloWorld.vue. Это компонент Single File, который разбит на три разных подраздела:
template: для компонентного HTML;
script: здесь компонентная логика реализована через JavaScript;
style: для стилей CSS.
Запустите dev-сервер:
$ cd client
$ npm run dev
Перейдите по адресу http://localhost:8080 в браузере. Вы должны увидеть следующее:
Добавьте новый компонент с именем Ping.vue в папку client/src/components:
Запустите приложение Flask в новом окне. В браузере по адресу http://localhost:8080 должно отобразиться «pong!». По сути, после ответа от серверной части устанавливаем в msg значение, полученное из data вернувшегося объекта.
Теперь можно приступить к созданию функциональности CRUD-приложения.
Что будем создавать?
Цель — разработать бэкенд RESTful API, работающий на Python и Flask, для единственного ресурса — книги. API должен следовать принципам разработки RESTful, используя основные HTTP-команды: GET, POST, PUT и DELETE.
GET-маршрут
Сервер
Добавим список книг в server/app.py:
BOOKS = [
{
'title': 'On the Road',
'author': 'Jack Kerouac',
'read': True
},
{
'title': 'Harry Potter and the Philosopher\'s Stone',
'author': 'J. K. Rowling',
'read': False
},
{
'title': 'Green Eggs and Ham',
'author': 'Dr. Seuss',
'read': True
}
]
После инициализации компонента вызываем метод getBooks() через хук жизненного цикла (lifecycle hook) created, который выбирает книги из только что настроенного маршрута на бэкенде.
Больше информации про Lifecycle Hook находится здесь.
В темплейте просматривается список книг с помощью директивы v-for, которая создаёт новую строку таблицы на каждой итерации. Значение индекса используется в качестве ключа (key). Затем используется директива v-if для отображения Yes или No — читал пользователь книгу или нет.
Bootstrap Vue
В следующем разделе используем компонент Modal для добавления новых книг. Для этого добавим библиотеку Bootstrap Vue, которая предоставляет набор Vue-компонентов, стилизованных с помощью HTML и CSS на основе Bootstrap.
Выбор Bootstrap Vue обоснован тем, что компонент Modal Bootstrap использует jQuery. Следует избегать совместного использования jQuery и Vue в одном проекте, поскольку последний использует Virtual Dom для обновления DOM-структуры. Другими словами, если вы используете jQuery для манипуляций с DOM, Vue об этом не узнает. По крайней мере, если вам необходимо использовать jQuery, не используйте его вместе с Vue на одних и тех же элементах DOM.
Установим:
$ npm install bootstrap-vue@2.0.0-rc.11 --save
Подключим библиотеку Bootstrap Vue в файле client/src/main.js:
import 'bootstrap/dist/css/bootstrap.css';
import BootstrapVue from 'bootstrap-vue';
import Vue from 'vue';
import App from './App';
import router from './router';
Vue.config.productionTip = false;
Vue.use(BootstrapVue);
/* eslint-отключение no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>',
});
POST-маршрут
Сервер
Обновим существующий обработчик маршрута для обработки POST-запросов для добавления новых книг:
Эту часть нужно добавить непосредственно перед закрывающим тегом </div>. Взгляните на код, v-model — это директива, используемая для привязки входных значений обратно к стейту.
Что делает Hide-Footer, вы можете просмотреть самостоятельно в документации по Bootstrap Vue.
addBookForm()привязывается к входным данным формы через v-model. Это называется двусторонней привязкой. Узнать об этом подробнее вы можете здесь.
onSubmit() запускается, когда пользователь успешно отправляет форму. При отправке предотвращается обычное поведение браузера (evt.preventDefault()), закрывается modal (this.$Refs.addBookModal.hide()), запускается метод addBook() и очищается форма (initForm()).
addBook() отправляет POST-запрос в /books для добавления новой книги.
Остальные изменения вы можете посмотреть самостоятельно в документации Vue по мере необходимости.
Теперь обновим кнопку «Add Book» в темплейте, чтобы при её нажатии отображался modal:
Можно выполнить проверку, попробовав добавить книгу.
Компонент Alert
Добавим компонент Alert для отображения конечному пользователю сообщения о том, что добавлена новая книга. Для этого создадим новый компонент, поскольку вполне вероятно, что вы захотите использовать эту функциональность в ряде других компонентов.
Добавим новый файл с именем Alert.vue в каталог client/src/components:
<template>
<p>It works!</p>
</template>
Затем импортируем его в разделе script компонента Books и зарегистрируем:
Для обновлений необходимо использовать уникальный идентификатор, поскольку нельзя полагаться на то, что заголовок книги будет уникальным. Можно использовать uuid из стандартной библиотеки Python.
Обновим BOOKS в server/app.py:
BOOKS = [
{
'id': uuid.uuid4().hex,
'title': 'On the Road',
'author': 'Jack Kerouac',
'read': True
},
{
'id': uuid.uuid4().hex,
'title': 'Harry Potter and the Philosopher\'s Stone',
'author': 'J. K. Rowling',
'read': False
},
{
'id': uuid.uuid4().hex,
'title': 'Green Eggs and Ham',
'author': 'Dr. Seuss',
'read': True
}
]
Также не забудьте импортировать:
import uuid
Рефакторинг all_books для учёта уникального идентификатора при добавлении новой книги:
Когда пользователь нажимает кнопку удаления, вызывается метод onDeleteBook(), который запускает другой метод removeBook(). Этот метод отправляет DELETE-запрос на сервер. Когда приходит ответ, отображается Alert и запускается getBooks().
Заключение
В этой статье были рассмотрены основы настройки CRUD-приложения с помощью Vue и Flask. Исходный код из тега v1 вы можете найти в репозитории flask-vue-crud.
Puter — интернет-ОС с открытым исходным кодом, предлагающая работу через браузер и возможность самохостинга. Проект, начавшийся как личная инициатива, уже собрал большое сообщество разработчиков. Puter обеспечивает легковесность, гибкость и интуитивно понятный интерфейс.