Consulta del matraz sqlalchemy con palabra clave como variable

Digamos que tengo un modelo como este:

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

Para obtener una lista de usuarios de Nueva York, esta es mi consulta:

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

Para obtener una lista de los usuarios que van a la USC, esta es mi consulta:

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

Y para obtener una lista de usuarios de Nueva York, y quienes van a la USC, esta es mi consulta:

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

Ahora, me gustaría generar dinámicamente estas consultas basadas en el valor de una variable.

Por ejemplo, mi variable podría verse así:

  {'hometown': 'New York'} 

O así:

  {'university': 'USC'} 

… O incluso así:

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

¿Puede ayudarme a escribir una función que tome un diccionario (o lista de diccionarios) como entrada y luego construya dinámicamente la consulta correcta de sqlalchemy?

Si trato de usar una variable para la palabra clave, obtengo este error:

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

En segundo lugar, no estoy seguro de cómo encadenar dinámicamente varias expresiones filter_by.

Puedo explícitamente, invocar una expresión filter_by, pero ¿cómo puedo encadenar varios en función de una variable?

Espero que esto tenga más sentido.

¡Gracias!

filter_by de SQLAlchemy toma argumentos de palabras clave:

filter_by (** kwargs)

En otras palabras, la función le permitirá asignarle cualquier parámetro de palabra clave. Es por esto que puede usar cualquier palabra clave que desee en su código: SQLAlchemy básicamente ve los argumentos en un diccionario de valores. Consulte el tutorial de Python para obtener más información sobre los argumentos de palabras clave.

Así que eso permite a los desarrolladores de SQLAlchemy recibir un conjunto arbitrario de argumentos de palabras clave en forma de diccionario. Pero está pidiendo lo contrario: ¿puede pasar un grupo arbitrario de argumentos de palabras clave a una función?

Resulta que en Python puedes hacerlo, usando una función llamada desempaquetar . Simplemente cree el diccionario de argumentos y páselo a la función precedida por ** , así:

 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') 

filter_by(**request.args) no funciona bien si tiene parámetros de consulta que no son del modelo, como la page de paginación, de lo contrario, obtendrá errores como estos:

 InvalidRequestError: Entity '' has no property 'page' 

Uso algo como esto que ignora los parámetros de consulta que no están en el modelo:

  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 

Considerando un modelo con una columna llamada valid , algo como esto funcionará:

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

se ignorará, la page está disponible para paginación y, lo mejor de todo, se generará el siguiente SQL: WHERE mymodel.valid in (1,2)

(obtenga el fragmento de código de arriba de forma gratuita si utiliza este módulo de ahorro de la plantilla )