flask sqlalchemy query with keyword as variable

匿名 (未验证) 提交于 2019-12-03 01:11:01

问题:

Let's say I have a model like this:

class User(db.Model):     id = db.Column(db.Integer, primary_key=True)     hometown = db.Column(db.String(140))     university = db.Column(db.String(140)) 

To get a list of users from New York, this is my query:

User.query.filter_by(hometown='New York').all() 

To get a list of users who go to USC, this is my query:

User.query.filter_by(university='USC').all() 

And to get a list of users from New York, and who go to USC, this is my query:

User.query.filter_by(hometown='New York').filter_by(university='USC').all() 

Now, I would like to dynamically generate these queries based on the value of a variable.

For example, my variable might look like this:

    {'hometown': 'New York'} 

Or like this:

    {'university': 'USC'} 

... Or even like this:

    [{'hometown': 'New York'}, {'university': 'USC'}] 

Can you help me out with writing a function which takes a dictionary (or list of dictionaries) as an input, and then dynamically builds the correct sqlalchemy query?

If I try to use a variable for the keyword, I get this err:

key = 'university' User.query.filter_by(key='USC').all()  InvalidRequestError: Entity '' has no property 'key' 

Secondly, I am not sure how to chain multiple filter_by expressions together dynamically.

I can explicitly, call out a filter_by expression, but how do I chain several together based on a variable?

Hope this makes more sense.

Thanks!

回答1:

SQLAlchemy's filter_by takes keyword arguments:

filter_by(**kwargs)

In other words, the function will allow you to give it any keyword parameter. This is why you can use any keyword that you want in your code: SQLAlchemy basically sees the arguments a dictionary of values. See the Python tutorial for more information on keyword arguments.

So that allows the developers of SQLAlchemy to receive an arbitrary bunch of keyword arguments in a dictionary form. But you're asking for the opposite: can you pass an arbitrary bunch of keyword arguments to a function?

It turns out that in Python you can, using a feature called unpacking. Simply create the dictionary of arguments and pass it to the function preceded by **, like so:

kwargs = {'hometown': 'New York', 'university' : 'USC'} User.query.filter_by(**kwargs) # This above line is equivalent to saying... User.query.filter_by(hometown='New York', university='USC') 


回答2:

filter_by(**request.args) doesn't work well if you have non-model query parameters, like page for pagination, otherwise you get errors like these:

InvalidRequestError: Entity '' has no property 'page' 

I use something like this which ignores query parameters not in the model:

    builder = MyModel.query     for key in request.args:         if hasattr(MyModel, key):             vals = request.args.getlist(key) # one or many             builder = builder.filter(getattr(MyModel, key).in_(vals))     if not 'page' in request.args:         resources = builder.all()     else:         resources = builder.paginate(             int(request.args['page'])).items 

Considering a model with a column called valid, something like this will work:

curl -XGET "http://0.0.0.0/mymodel_endpoint?page=1&valid=2&invalid=whatever&valid=1" 

invalid will be ignored, and page is available for pagination and best of all, the following SQL will be generated: WHERE mymodel.valid in (1,2)

(get the above snippet for free if you use this boilerplate-saving module)



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!