I am working on a flask project and I am stuck on an issue where I am trying to add a case statement to a query as a column.
I have tried lots of potential solutions and the closest I have found so far is add_columns()
the problem is that this makes the query return a tuple with the object of the model I queried and result from the case statement, what I want is just the model object that has the result of the case in it.
here is some simplified code that shows my issue
from flask import Flask
from sqlalchemy.sql.expression import case
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///database.db"
db = SQLAlchemy(app)
class Image(db.Model):
__tablename__ = 'images'
id = db.Column(db.Integer, primary_key=True)
url = db.Column(db.Text)
model_id = db.Column(db.Integer)
db.create_all()
@app.route('/')
def hello_world():
image_ids = [1, 2, 3, 4, 5]
image_weights = [0.1, 0.4, 0.23232, 0.21, 0.001]
print(list(zip(image_ids, image_weights)))
case_statement = case(
[(uid == Image.id, weight) for uid, weight in zip(image_ids, image_weights)]
)
results = db.session.query(Image).add_columns(case_statement.label("weight")).filter(
Image.id.in_(image_ids)).order_by("weight")
print(results)
print(results.all())
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True)
the output of print(results.statement.compile(compile_kwargs={"literal_binds": True}))
is
SELECT images.id,
images.url,
images.model_id,
CASE WHEN (images.id = 1) THEN 0.1 WHEN (images.id = 2) THEN 0.4 WHEN (images.id = 3) THEN 0.23232 WHEN (images.id = 4) THEN 0.21 WHEN (images.id = 5) THEN 0.001 END AS weight
FROM images
WHERE images.id IN (1, 2, 3, 4, 5)
ORDER BY weight;
the output of print(results.all())
[(<Image 5>, 0.001), (<Image 1>, 0.1), (<Image 4>, 0.21), (<Image 3>, 0.23232), (<Image 2>, 0.4)]
the result I am looking for is
[<Image 5>, <Image 1>, <Image 4>, <Image 3>, <Image 2>]
One easy solution to this is to just go over each item in the list of results and use setattr to set a attribute weight of the image object to the second item in the tuple but I can't do this as I want to make a function that returns a query object with the filters applied not a list of objects