How to do a sqlalchemy query using a string variable as table name?

橙三吉。 提交于 2020-01-23 03:44:48

问题


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

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