Дизайн API с использованием Flask, сочетающий SQL Alchemy и Marshmallow

Я создаю простое приложение 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. На самом деле у меня будет больше, например. дата создания, дата обновления, описание и т. д.

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, так что мне не нужно их повторять. Я прав?


person GRS    schedule 10.04.2020    source источник


Ответы (1)


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

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

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

post = models.Post(**data)

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

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

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

person Jérôme    schedule 11.04.2020