Я пытаюсь использовать flask-rest-api в качестве основы для простого примера веб-сервиса с SQLAlchemy в качестве ORM.Все работает отлично, за исключением случаев, когда дело касается обновлений.
Вот код, о котором идет речь:
@blp.arguments(DogSchema)
@blp.response(DogSchema)
def put(self, data, dog_id):
"""Update existing dog"""
try:
dog = Dog.query.get(dog_id)
except Exception as e:
abort(404, message="Item not found - %s" % e)
# update the dog here
return dog
Когда это выполняется, переменная data
является временным объектом модели Dog.flask-rest-api заботится о десериализации данных в запросе JSON, просмотре вашей схемы Marshmallow и создании объекта модели sqlalchemy правильного типа.
Вот моя модель и схемы для полноты:
class Dog(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String, nullable=False)
@api.definition("Dog")
class DogSchema(ma.ModelSchema):
class Meta:
model = Dog
strict = True
ordered = True
id = field_for(Dog, 'id', dump_only=True)
То, что я хотел бы сделать, это просто взять временный объект и обновить объект в сеансе со всеми атрибутами.
Мне удалось сделать это двумя разными способами, нииз которых мне нравится, и я надеюсь, что есть лучший способ сделать это.
1) через слияние
@blp.arguments(DogSchema)
@blp.response(DogSchema)
def put(self, data, dog_id):
"""Update existing dog"""
try:
dog = Dog.query.get(dog_id)
except Exception as e:
abort(404, message="Item not found - %s" % e)
data.id = dog_id
db.session.merge(data)
db.session.commit()
return dog
Это работает, но слияние, похоже, имеет другие побочные эффекты - этоизвлекает из базы данных, если записи нет в сеансе, и если ее нет в базе данных, добавляет ее.
2) С помощью сериализации зефира
@blp.arguments(DogSchema)
@blp.response(DogSchema)
def put(self, data, dog_id):
"""Update existing dog"""
try:
dog = Dog.query.get(dog_id)
except Exception as e:
abort(404, message="Item not found - %s" % e)
serializer = DogSchema()
serializer.load(serializer.dump(data).data, instance=dog, session=db.session, partial=True)
db.session.commit()
return dog
ИспользуетсяMarshmallow, чтобы сериализовать переменную data
обратно в JSON, а затем загрузить ее обратно, что кажется довольно неэффективным.
Мне бы очень хотелось, чтобы было что-то столь же простое, как
@blp.arguments(DogSchema)
@blp.response(DogSchema)
def put(self, data, dog_id):
"""Update existing dog"""
try:
dog = Dog.query.get(dog_id)
except Exception as e:
abort(404, message="Item not found - %s" % e)
dog.update(data)
db.session.commit()
return dog
но это не похоже нараунд, так что надеюсь, что кто-то может мне помочь.
Спасибо!