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

  • Создать базу данных
  • Проектировать схему базы данных и отношения
  • Используйте уровень абстракции данных платформы для реализации модели базы данных и необходимых запросов.
  • Запустите миграцию базы данных, чтобы применить разработанную схему к целевой базе данных.

В последнем эпизоде я писал о том, как инициировать приложение Flask. Здесь я покажу, как создать схему базы данных в Flask.

Примечание. Я предлагаю просмотреть последний выпуск, поскольку мы используем один и тот же исходный код.

Давайте начнем!

Создайте базу данных и настройте соединение

В этой настройке мы используем Postgres в качестве нашего механизма базы данных. В установку Postgres не вникаю, но если хотите установить, то можете посмотреть здесь. (Дебиан)

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

:$ sudo -u postgres psql 
> CREATE USER cool_user WITH PASSWORD '1234';

Пользователь базы данных cool_user и пароль 1234.

Затем нам нужно создать базу данных. Внутри оболочки Postgres запустите:

> CREATE DATABASE cool_db;

Последний шаг — предоставить необходимое разрешение пользователю cool_user для базы данных cool_db:

> GRANT ALL PRIVILEGES ON DATABASE cool_db TO cool_user;

Примечание. При этом предоставляются все разрешения. В реальной настройке просто дайте необходимые разрешения из соображений безопасности.

После настройки базы данных нам нужно настроить наше приложение Flask.

В сценарии config.py мы должны ввести две новые переменные:

  • SQLALCHEMY_DATABASE_URI: это параметр подключения к базе данных. Формат: postgresql://DATABASE_USER:PASSWORD@DATABASE_HOST_NAME:DATABASE_PORT/DATABASE_NAME
  • SQLALCHEMY_TRACK_MODIFICATIONS: SQLAlchemy отслеживает модификации объектов базы данных и выдает сигналы для уведомления приложения об изменениях. Включение этого может привести к увеличению производительности для больших приложений. Тщательно выбирайте.

Это config.py

class CoolConfig(object):
    SQLALCHEMY_DATABASE_URI = "postgresql://cool_user:1234@localhost:5432/cool_db"
    SQLALCHEMY_TRACK_MODIFICATIONS = False

Примечание. Наша база данных работает на локальном хосте. 5432 — порт Postgres по умолчанию.

Прежде чем мы реализуем нашу схему базы данных, нам нужно импортировать объект базы данных в наше приложение, чтобы использовать его. Для этого создайте новое имя скрипта databse.py непосредственно в приложении и создайте объект:

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

Таким образом мы делаем объект базы данных доступным глобально в нашем приложении.

Реализуйте схему: модель колбы

Прежде чем мы реализуем нашу схему, нам нужно смоделировать ее в уме. В этом примере мы хотим смоделировать автомобили, которые покупают пользователи:

  • Нам нужны две таблицы: users и cars.
  • Столбцы таблицы пользователей: идентификатор (первичный ключ), имя пользователя, created_at (дата регистрации пользователя), роль (роли пользователей в нашей системе: ученик, учитель и сотрудник)
  • Столбцы таблицы cars: id (первичный ключ), model (название автомобиля) и owner_id (кто купил, идентификатор пользователя).
  • Каждый пользователь может покупать автомобили один ко многим

Обладая этими знаниями, мы создаем модели нашего приложения Flask. Модели:

  • Классы Python
  • Уровень абстракции данных
  • Избавьте нас от написания сложных SQL-запросов
  • Мы используем их для определения схемы базы данных
  • Мы также используем их для всех функций, которые взаимодействуют со слоем данных.

В каталоге приложения создайте новое имя каталога models. Мы размещаем здесь наши модели.

Затем внутри этого каталога создайте имя сценария user.py. Поместите в него этот код:

from best_app.database import db

class User(db.Model):
    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(), unique=True, nullable=False)    
    created_at = db.Column(db.Date, nullable=False)
    role = db.Column(db.String(), default="employee")    

    __table_args__ = (
        db.CheckConstraint(role.in_(['student', 'teacher', 'employee']), name='role_types'),      
    )


    def __init__(self, username, created_at, role):
        self.username = username        
        self.created_at = created_at        
        self.role = role
    
    def register_user_if_not_exist(self):        
        db_user = User.query.filter(User.username == self.username).all()
        if not db_user:
            db.session.add(self)
            db.session.commit()
        
        return True
    
    def get_by_username(username):        
        db_user = User.query.filter(User.username == username).first()
        return db_user

    def __repr__(self):
        return f"<User {self.username}>"
  • Это наш модельный класс для таблицы пользователей.
  • Обратите внимание, что мы сначала импортировали объект db, который создали ранее, в database.py.
  • Во-первых, мы определяем имя нашей таблицы, используя __tablename__.
  • Затем мы вводим столбцы нашей таблицы, которые являются свойствами класса.
  • Мы также создаем специальные ограничения для столбца role, используя __table_args__. (Имя ограничения произвольно)
  • После этого конструктор класса
  • Затем мы реализуем две функции для регистрации пользователя и выбора пользователя на основе заданного имени пользователя. Обратите внимание, что вам не нужны SQL-запросы.
  • В конце концов, это строковое представление модели, если мы хотим, например, напечатать пользовательский объект.

Теперь реализуем табличную модель cars. В том же каталоге models создайте новый скрипт с именем car.py и вставьте в него следующее:

from best_app.database import db
from best_app.models.user import User
from sqlalchemy import ForeignKeyConstraint

class Car(db.Model):
    __tablename__ = 'cars'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)     
    model = db.Column(db.String(), nullable=False)
    owner_id = db.Column(db.Integer, nullable=False)    
    
    __table_args__ = (        
        ForeignKeyConstraint([owner_id], [User.id], ondelete='NO ACTION'),        
    )


    def __init__(self, model, owner_id):
        self.model = model
        self.owner_id = owner_id      
    
    def to_dict(self):
        return {
            'model': self.model,
            'owner': self.owner_id            
        }
    
    def buy_car(self):
        record = Car.query.filter(Car.id == self.id).first()
        if not record:
            db.session.add(self)
            db.session.commit()
        
        return True

    def get_user_cars(user_id):
        records = Car.query.filter(Car.owner_id == user_id).all()
        return [record.to_dict() for record in records] 

    def __repr__(self):
        return f"<Car {self.model}>"

Раздел почти такой же, как UserModel. Кроме:

  • У нас есть новое ограничение: ForeignKey. Это идентификатор пользователя, который указал, кто купил этот автомобиль. Политика ondelete сообщает базе данных, что должно произойти при удалении пользователя. Здесь мы говорим ему ничего не делать. Но мы также можем изменить другие политики, такие как каскад, которые также удаляют все автомобили, связанные с удаленным пользователем. "Читать далее"
  • Мы также реализуем функцию to_dict. Эта функция преобразует объект SQLAlchemy в словарь. Почему? потому что объекты SQLAlchemy не сериализуемы в формате JSON. Поэтому мы сталкиваемся с проблемами, если хотим вернуть список автомобилей клиенту приложения в формате JSON. Кроме того, мы можем контролировать, что выставлять из этой таблицы.
  • После этого мы реализуем две функции для покупки автомобиля и возврата списка всех автомобилей, купленных пользователем.

Итак, наши модели готовы. Однако в нашей базе данных Postgres по-прежнему нет таблиц. Нам нужны последние шаги.

Инициация и миграция базы данных

Последний шаг — использовать наши модели и инициировать таблицы базы данных. Для этого мы используем библиотеку Flask Migration. Нам также понадобится Postgres Database Adopter для Python. Активируйте виртуальную среду Python приложения Flask и запустите:

(.venv) > pip install Flask-Migrate
(.venv) > pip install psycopg2

После этого нам нужно сделать три важные вещи:

  • инициировать объект db для нашего приложения
  • Зарегистрируйте наши модели (Пользователь и Автомобиль)
  • Загрузите объект миграции для Flask

Мы делаем все эти шаги внутри нашей фабрики приложений:

from flask import Flask
from best_app.modules import hello, goodbye
from best_app.config import CoolConfig
from flask_migrate import Migrate
from best_app.database import db


def create_app():    
    app = Flask(__name__)        
    app.config.from_mapping(
        SECRET_KEY = "My_Secret_Key"
    )     
    
    app.config.from_object(CoolConfig)    
    
    # Database related part
    db.init_app(app)
    from best_app.models.user import User
    from best_app.models.car import Car
    migrate = Migrate(app, db)

    app.register_blueprint(hello.blueprint)
    app.register_blueprint(goodbye.blueprint)

    return app

Последним шагом будет создание наших таблиц. Запустите это в командной строке (venv включен)

(.venv) > export FLASK_APP=best_app
(.venv) > flask db init
(.venv) > flask db migrate
(.venv) > flask db upgrade

Примечания:

  • Вам нужно запустить db init только при первом запуске вашей базы данных.
  • команда migrate создает сценарий миграции (SQL-версию вашей модели) внутри вашего приложения.
  • Команда обновления — это та команда, которая фактически запускает миграцию в вашей базе данных.
  • Каждый раз, когда вы меняете свою схему, вам нужно запускать команды миграции и обновления.

Вот и все! Наша база данных готова к использованию!

Вы можете найти исходный код здесь: https://github.com/Pooya-Oladazimi/flask-cool-app

Надеюсь, это будет полезно для вас!

Этот пост изначально был опубликован в моем блоге: https://www.polaz.net/flask-app-postgres-database-initialization-step-by-step-guide-with-models/

Конец.