API дизайн с использованием Flask, объединяющий SQL Алхимия и Зефир - PullRequest
0 голосов
/ 10 апреля 2020

Я создаю простое приложение CRUD. Я использую Flask, и я решил использовать SQLAlchemy в качестве ORM и Marshmallow для проверки полезных нагрузок.

Моя проблема в настоящее время состоит в том, чтобы минимизировать количество репликации, которое мне нужно написать.

В данном случае мы просто имеем дело с сообщениями.

Создание

models.py

class Post(Base):
    __tablename__ = 'posts'

    id = Column(UUID(as_uuid=True), primary_key=True)
    user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'))
    title = Column(String(length=50)) 

schemas.py

class CreatePostSchema(Schema):
    title = fields.Str(required=True)

Мне не нужны id и user_id, так как они будут созданы / найдены бэкэндом, но все остальные поля являются обязательными.

Я использую BluePrints, и один из маршрутов / конечных точек, связанных с созданием постов, будет иметь метод post().

Я могу создать декораторы, чтобы сначала убедиться, что схема правильная, получить пользователя и передать его в метод post:

@auth_required()
@validate_schema(CreatePostSchema)
def post(request, user_id, cleaned_schema):
    create_post(cleaned_schema)
    return 200

Теперь я могу написать create_post() функционировать без таких жестких клавиш, как:

def create_post(user_id, **clean_data)
    post = models.Post(**clean_data)
    post.user_id = user_id

Но разве это хорошая практика? Или я должен явно указать ключи вроде:

def create_post(user_id, title)
    post = models.Post(title=title)
    post.user_id = user_id
    post.id = uuid4()
    return post

Тогда у меня также возникает вопрос, на каком этапе выполнять проверку. Должна ли валидация происходить перед методом post() или во время создания поста? Например, я мог бы сделать что-то вроде:

def create_post(user_id, **data):
    clean_data = CreatePostSchema.load(**data)
    post = models.Post(**clean_data)
    session.add(post)
    session.commit()
    return

Таким образом, я могу удалить дополнительный @has_schema() декоратор.

Обновление

Обновление - это другой зверь, чтобы писать без повторяющиеся ключи. Давайте предположим, что у нас есть только 1 поле и EditPostSchema = CreatePostSchema. На самом деле у меня будет больше, например, дата создания, дата обновления, описание и т. Д. c.

clean_data = EditPostSchema.load(**data)
id = clean_data.pop('id')
update_post(id, clean_data)

def update_post(id, **clean_data):
    session.query(Post).get(id).update(**clean_data, synchronize_session=False)
    return

Итак, по сути, я думаю, что Schemas уже должен объяснить поля, которые мне нужны для CRUD так что мне не нужно их повторять. Я прав?

1 Ответ

1 голос
/ 11 апреля 2020

Вы можете использовать webargs для проверки входных данных схемами зефира.

Если вы хотите избежать дублирования кода, вы также можете попробовать marshmallow-sqlalchemy для генерации Схемы API из модели.

Если API достаточно близок к модели, вы можете создать объект, передавая входные данные в POST:

post = models.Post(**data)

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

Вы можете закодировать поля, которые хотите обновить.

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

...