В этом руководстве я подробно расскажу, как создать приложение CRUD с помощью API RESTful, используя Flask. Если у вас есть данные, которыми вы хотите поделиться со всем миром, API - это один из способов получить их в руки других. Однако API-интерфейсы не всегда являются лучшим способом обмена данными с пользователями. Если размер предоставляемых вами данных относительно невелик, вы можете вместо этого предоставить «дамп данных» в виде загружаемого файла JSON или XML. Мы будем тестировать наши конечные точки с помощью PostMan, чтобы убедиться, что наши конечные точки работают. MYSQL - самая популярная система управления реляционными базами данных с открытым исходным кодом. Мы будем использовать MYSQL для сохранения наших записей в базе данных.

Предварительные требования:
1. Python3.
2. Сервер MYSQL загружен и готов к работе (будет рассмотрен подробно).
3. Flask (будет рассмотрен более подробно).

Настройка нашей серверной среды

Мы можем начать с загрузки сервера MYSQL https://dev.mysql.com/downloads/ и запуска его на вашем компьютере.

  • Затем мы можем выполнить несколько команд перед созданием приложения:
$ pip3 install flask
$ brew install mysql
  • Теперь у нас есть среда, готовая начать работу с учебником.

Создание наших учетных данных для базы данных

В этом разделе рассказывается, как создавать учетные записи пользователей MYSQL и предоставлять привилегии.

  • Чтобы получить доступ к оболочке MYSQL, введите следующую команду и при появлении запроса введите пароль пользователя root MYSQL:
$ mysql -u root -p
  • Чтобы создать новую учетную запись пользователя MYSQL, выполните следующую команду:
mysql> CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'user_password';
  • Предоставьте все привилегии учетной записи пользователя во всех базах данных:
mysql> GRANT ALL PRIVILEGES ON *.* TO 'database_user'@'localhost';
  • Имя создания базы данных:
mysql> CREATE DATABASE database_name;

Давайте создадим дерево нашего проекта, чтобы начать кодирование

  • Ниже вы можете просмотреть дерево проекта:
fullstack-blog/
    app.py
    config.py
    Model.py
    run.py
    migrate.py
    requirements.txt
    resources/
       Details.py
       TemplateRender.py
       User.py
    templates/
       addDetails.html
       addUser.html
       main.html
  • Для построения дерева проекта предусмотрены следующие команды:
$ mkdir fullstack-blog
$ cd fullstack-blog
$ touch app.py config.py Model.py run.py migrate.py requirements.txt
$ mkdir resources templates
$ cd resources
$ touch Details.py TemplateRender.py User.py
$ cd templates
$ touch addDetails.html addUser.html

Теперь, когда окружение и дерево нашего проекта готовы, давайте запачкаем руки!

  1. В этой части основное внимание уделяется созданию серверной части путем создания таблиц в Model.py файле.
from flask import Flask
from marshmallow import Schema, fields, pre_load, validate, ValidationError
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy
ma = Marshmallow()
db = SQLAlchemy()

class User(db.Model):
   __tablename__ = 'user'
   id = db.Column(db.Integer, primary_key=True)
   first_name = db.Column(db.String(150), nullable=False)
   last_name = db.Column(db.String(150), unique=True,    nullable=False)
   details = db.relationship('Detailes', backref=db.backref('user',   lazy=True))

def __init__(self, first_name, last_name):
   self.first_name = first_name
   self.last_name = last_name
class Detailes(db.Model):
   __tablename__ = 'details'
   id = db.Column(db.Integer, primary_key=True)
   age = db.Column(db.Integer, unique=True, nullable=False)
   address = db.Column(db.String(150), unique=True, nullable=False)
   country_origin = db.Column(db.String(150), unique=True, nullable=False)
   user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True)
def __init__(self, age, address, country_origin):
   self.age = age
   self.address = address
   self.country_origin = country_origin
class UserSchema(ma.Schema):
   id = fields.Integer(dump_only=True)
   first_name = fields.String(required=True)
   last_name  = fields.String(required=True)
class DetailesSchema(ma.Schema):
   id = fields.Integer(dump_only=True)
   age = fields.Integer(required=True)
   address = fields.String(required=True)
   country_origin = fields.String(required=True)
   user_id = fields.Integer(required=False)
  • Этот фрагмент кода создает две таблицы: User и Details. Он также создал свои схемы для сериализации и десериализации данных.
  • Обе таблицы имеют назначенные отношения один-ко-многим с использованием details = db.relationship ('Detailes', backref = db.backref ('user', lazy = True)) и user_id = db.Column (db.Integer, db. ForeignKey ('user.id'), nullable = True), чтобы предоставить FK, на который ссылается таблица User.

2. Затем создайте соединение с сервером базы данных MYSQL под файлом config.py

import os

basedir = os.path.abspath(os.path.dirname(__file__))
SQLALCHEMY_ECHO = False
SQLALCHEMY_TRACK_MODIFICATIONS = True
SQLALCHEMY_DATABASE_URI = "mysql+pymysql://flask_user:1234@localhost/flaskapp"
  • Помните, что мы создали пользователя в оболочке MYSQL и предоставили все привилегии учетной записи пользователя во всех базах данных. Теперь мы можем заменить имя пользователя вместо flask_user и созданный пароль вместо 1234. /flaskapp - это имя нашей базы данных, которую мы можем создать.

3. Теперь добавьте следующие изменения в run.py файл, отвечающий за локальный запуск приложения flask.

from flask import Flask
from flask_cors import CORS
def create_app(config_filename):
   app = Flask(__name__)
   CORS(app)
   app.config.from_object(config_filename)

   from app import api_bp, template_bp
   app.register_blueprint(api_bp, url_prefix='/api')
   app.register_blueprint(template_bp, url_prefix='/')

   from Model import db
   db.init_app(app)

   return app

if __name__ == "__main__":
   app = create_app("config")
   app.run(host='0.0.0.0')
  • В этой части мы добавили чертежи к нашим двум основным конечным точкам /api и /, в которых мы разделяем конечные точки, связанные с нашими API, и конечные точки, которые обрабатывают отрисовку наших шаблонов. Также мы добавили все необходимые строки, которые обрабатывают запуск нашего приложения локально. Мы можем запустить наше приложение с помощью команды python3 run.py, но я предпочитаю создавать файлы миграции перед этим.

4. Создайте миграции, чтобы перенести все изменения, добавленные в сервер базы данных MYSQL.

from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from Model import db
from run import create_app
app = create_app('config')

migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)

if __name__=="__main__":
   manager.run()
  • Теперь мы можем запустить файл migrate.py, используя следующие команды:
$ python3 migrate.py db init
$ python3 migrate.py db migrate
$ python3 migrate.py db upgrade

5. Если до сих пор все работает нормально, перейдите и создайте файлы в каталоге ресурсов. Следующий код добавляет изменения в User.py файл:

from flask import request
from flask_restful import Resource
from Model import db, User, UserSchema
import json
users_schema = UserSchema(many=True)
user_schema = UserSchema()
class UserResource(Resource):
   @staticmethod
   def get():
      users = User.query.all()
      users = json.dumps(users)
      return {'status': 'success', 'data': users}, 200
   @staticmethod
   def post():
      json_data = request.get_json(force=True)
      if not json_data:
         return {'message': 'No input data provided'}, 400
      # Validate and deserialize input
     response = json.dumps(json_data)
     data = user_schema.loads(response)
     user = User.query.filter_by(first_name=data['first_name']).first()
     if user:
        return {'message': 'User already exists'}, 400
     user = User(
     first_name=data['first_name'],
     last_name=data['last_name']
     )
    db.session.add(user)
    db.session.commit()
    result = user_schema.dump(user)
    return {"status": 'success', 'data': result}, 201

В этой части мы создали два метода Restful, GET и POST.
Мы также позаботились о том, чтобы в случае POST запроса мы обрабатывали некоторые ошибки, которые могут возникнуть во время тестирования. Метод GET будет отвечать за получение всех пользовательских записей, сохраненных в нашей базе данных. Метод POST будет отвечать за добавление новых записей в нашу базу данных.

  • Мы можем сделать то же самое для Details таблицы, но изменить все поля ввода данных, которые связаны с Details таблицей.
  • Двигаясь дальше, добавьте в TemplateRender.py код, который поможет в рендеринге шаблонов. У нас есть три шаблона: шаблон main.html, который считается шаблоном индекса проекта, addUser.html и addDetails.html шаблоны, содержащие код, который выполняет POST запрос на добавление записей в нашу базу данных.
from flask import request, render_template, make_response
from flask_restful import Resource
class IndexResource(Resource):
   @staticmethod
   def get():
   headers = {'Content-Type': 'text/html'}
   return make_response(render_template('main.html'),200,headers)
class AddUser(Resource):
   @staticmethod
   def get():
   headers = {'Content-Type': 'text/html'}
   return make_response(render_template('addUser.html'),200,headers)
class AddDetails(Resource):
   @staticmethod
   def get():
   headers = {'Content-Type': 'text/html'}
   return = make_response(render_template('addDetails.html'),200,headers)
  • Здесь добавлено GET запросов на получение отрисованных шаблонов.

6. Эта часть создает все наши маршруты в файле app.py.

from flask import Blueprint
from flask_restful import Api
from resources.User import UserResource
from resources.Details import DetailsResource
from resources.TemplateRender import IndexResource, AddUser, AddDetails
api_bp = Blueprint('api', __name__)
api = Api(api_bp)
template_bp = Blueprint('template', __name__)
template = Api(template_bp)
# Route
template.add_resource(IndexResource, '/')
template.add_resource(AddUser, 'addUser')
template.add_resource(AddDetails, 'addDetails')
api.add_resource(UserResource, '/User')
api.add_resource(DetailsResource, '/Details')
  • Используя схему, обратите внимание, что мы создали две схемы: одну для APIs , а другую - для шаблонов. Эта часть также содержит все маршруты, которые будут использоваться в проекте.
  • Ниже вы можете найти таблицу с разбивкой всех возможных маршрутов и методов Restful на данный момент:

  • Выполнение некоторых тестов с использованием POSTMAN на наших созданных конечных точках API:

POST-запрос для пользователя:

POST-запрос для получения подробной информации:

Получить запрос подробностей:

Чтобы дважды проверить, что метод POST вставил записи, предоставленные в таблицы базы данных, я использовал «SequelPro»:

7. Переходя к созданному простому интерфейсу, давайте добавим следующий код HTML, JavaScript и CSS в наш addUser.html файл в директории templates.

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">

<style>
body {font-family: Arial, Helvetica, sans-serif;}
* {box-sizing: border-box;}

input[type=text], select, textarea {
   width: 100%;
   padding: 12px;
   border: 1px solid #ccc;
   border-radius: 4px;
   box-sizing: border-box;
   margin-top: 6px;
   margin-bottom: 16px;
   resize: vertical;
}
input[type=submit] {
   background-color: #4CAF50;
   color: white;
   padding: 12px 20px;
   border: none;
   border-radius: 4px;
   cursor: pointer;
}
input[type=submit]:hover {
background-color: #45a049;
}
.container {
border-radius: 5px;
background-color: #f2f2f2;
padding: 20px;
}
</style>

</head>
<body>
<h3>User Form</h3>
<div class="container">
  <form action="/action_page.php">
    <label for="fname">FirstName</label>
    <input type="text" id="fname" name="firstname" placeholder="First Name..">
    <label for="lname">LastName</label>
    <input type="text" id="lname" name="lastname" placeholder="Last Name..">
    <input id= "submit" type="submit" value="Submit">
  </form>
</div>
<script type=text/javascript>
$(document).ready(function () {
  var first_name = $('#fname').val();
  var last_name = $('#lname').val();

  $("#submit").click(function () {
     $.ajax({
        type: 'POST',
        data: {first_name: first_name, last_name: last_name},
        url: "https://0.0.0.0:5000/api/User"
      });
   });
});
</script>
</body>
</html>

8. Заключительные шаги: все вместе:

  • Чтобы проверить наши изменения, давайте запустим наше приложение, используя следующую команду:
$ python3 run.py

Идите вперед и получите доступ к нему локально, используя ваш браузер по URL-адресу https://0.0.0.0:5000/.

Вы можете увидеть шаблон main.html, отображаемый, поскольку он является нашей точкой входа.

Если мы перешли по URL-адресу https://0.0.0.0:5000/addUser, то увидим, что шаблон addUser.html визуализирован.

Вывод

  • Мы узнали, как получить доступ и создать пользователя базы данных с помощью сервера MYSQL.
  • Мы узнали, как создать дерево нашего проекта.
  • Мы создали все Restful API проекта, используя фляжку и зефир.
  • Мы создали схемы, чтобы отделить конечные точки API от конечных точек рендеринга шаблонов.
  • Мы протестировали наши конечные точки API с помощью PostMan.
  • Мы протестировали наши шаблоны, отображаемые локально, с использованием наших URL-адресов.
  • Исходный код: https://github.com/Islamnader94/FlaskApp