问题
I apologize in advance if I am not clear, English is not my native language. Feel free to tell me if I make too many mistakes :)
I am a newbie in using flask_sqlalchemy and get frustrated after spending hours on Internet searching for an answer.
What I want is doing a query like that one :
ModelName.query.filter_by(name='something').all()
But instead of using ModelName I want to do something like that :
model_list = ['Model1', 'Model2', 'Model3']
for model in model_list:
some_var = model.query.filter_by(name='something').all()
# do some stuff with the variable
The error is :
'str' object has no attribute 'query'
I have of course the same kind of problem when trying to use db.session.add() with a string variable.
I understand that the query requires some kind of _BoundDeclarativeMeta object instead of a string but then how to get that object from a list to pass it to a for loop ?
I tryed using 'db.metadata.tables[my_variable]' but I get a Table object instead of a _BoundDeclarativeMeta object and it doesn't work the same.
I manage to do a query using
db.session.query(db.metadata.tables[my_variable])
instead of
my_variable.query
but I can't use that method for the 'db.session.add()' (or is it possible ?)
Is there any way to 'cast' the string variable into the right type of sqlalchemy object ?
回答1:
Try this:
mapping_str_to_object = {}
for model in BaseModel._decl_class_registry.values():
if hasattr(model, '__tablename__'):
mapping_str_to_object[model.__tablename__] = model
model_list = ['Model1', 'Model2', 'Model3']
for model in model_list:
some_var = mapping_str_to_object[model].query.filter_by(name='something').all()
回答2:
Hope it's not too late. I think you can try this:
class Model1:
pass
class Model2:
pass
model_list = [Model1, Model2]
for model in model_list:
db.session.query(model)
Model1 and Model2 are classes like Users, Roles ,etc.
回答3:
I think importlib
may help you here if you are using python > 2.7
importlib.import_module('module to import')
For your case: If your project structure looks like below and models.py defines all the OR mapped classes.
a
|
+ - __init__.py
- b
|
+ - __init__.py
- models.py
The code should be like:
model_list = ['Model1', 'Model2', 'Model3']
the_module = importlib.import_module('module to import') # eg. importlib.import_module('a.b.models')
for model in model_list:
the_class = getattr(the_module, model)
some_var = the_class.query.filter_by(name='something').all()
回答4:
I needed a way to query by referring to the model's tablename. This is what I came up with:
class Model1(db.Model):
__tablename__ = 'table1' # or whatever, doesn't matter
class Model2(db.Model):
__tablename__ = 'table2'
tables_dict = {table.__tablename__: table for table in db.Model.__subclasses__()}
def table_object(table_name):
return tables_dict.get(table_name)
Then, use it like this:
model_list = ['table1', 'table2']
for model in model_list:
some_var = db.session.query(table_object(table_name=model)).filter_by(name='something').all()
The important bit is db.Model.__subclasses__()
- gives a list of the model classes (objects?).
回答5:
I sort of managed to get what I wanted using
eval(my_variable)
It seems that eval() allow me to get a db object named by the variable value rather than a plain string object.
I saw security warnings about the use of eval() but I gess it's OK since the evaluated variable doesn't come from user input.
Of course if anyone sees a better way to do the same thing I would be glad know it.
来源:https://stackoverflow.com/questions/41176006/how-to-do-a-sqlalchemy-query-using-a-string-variable-as-table-name