I'm trying to use flask-rest-api as a framework for a simple example webservice with SQLAlchemy as the ORM. Everything works fine, except when dealing with updates.
Here's the code in question:
@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
When this executes, the data
variable is a transient Dog model object. flask-rest-api takes care of unserializing the data in the JSON request, looking at your Marshmallow schema and creating a sqlalchemy Model object of the correct type.
Here's my model and schemas for completeness sake:
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)
What I'd like to do is just take the transient object and update the object in the session with all the attributes.
I've been able to do this two different ways, neither of which I like and I'm hoping there is a better way of doing this.
@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
This works, but merge seems to have other side effects - it pulls from the db if the record isn't in the session, and if it doesn't exist in the db, adds it.
@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
This uses Marshmallow to serialize the data
variable back to JSON, then load it back in, which seems rather inefficient.
I'd really love there to be something as simple as
@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
but that doesn't seem to be around, so hoping someone can help me out.
Thanks!
Update table elements in SQLAlchemy. Get the books to table from the Metadata object initialized while connecting to the database. Pass the update query to the execute() function and get all the results using fetchall() function. Use a for loop to iterate through the results.
_sa_instance_state is a non-database-persisted value used by SQLAlchemy internally (it refers to the InstanceState for the instance.
Python Flask and SQLAlchemy ORM To modify data of a certain attribute of any object, we have to assign new value to it and commit the changes to make the change persistent. SELECT customers.id AS customers_id, customers.name AS customers_name, customers. address AS customers_address, customers.
You can specify update
method for you Dog
class:
class Dog(db.Model):
...
def update(self, data):
for k, v in data.items():
setattr(self, k, v)
return self
And then use it as you wanted:
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With