Flask - Convert request.args to dict - sqlalchemy

I've been trying to figure out how to pass the request.args to sqlalchemy filter.
I thought this should work:
model.query.filter(**request.args).all()
But it's throwing the error:
TypeError: <lambda>() got an unexpected keyword argument 'userid'
When userid or any other get arg is present.
According to this post - https://stackoverflow.com/questions/19506105/flask-sqlalchemy-query-with-keyword-as-variable - you can pass a dict to the filter function.
Any ideas what I'm doing wrong?
Many thanks :)
UPDATE: Many thanks to the poster below, however now it's throwing the following error:
ProgrammingError: (ProgrammingError) (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') ORDER BY tblclients.clientname' at line 3") 'SELECT favourites.id AS favourites_id, favourites.userid AS favourites_userid, favourites.clientid AS favourites_clientid, favourites.last_visit AS favourites_last_visit \nFROM favourites INNER JOIN tblclients ON tblclients.clientid = favourites.clientid \nWHERE favourites.userid = %s ORDER BY tblclients.clientname' ([u'41'],)
Any ideas?

First, you have to use filter_by, not filter.
Second, Flask request.args uses a MultiDict, a dict with the values inside a list, allowing more than one value for the same key, because the same field can appear more than once in a querystring. You got the error because the SQL query got the [u'41'] when it expected only '41'. You can use request.args.to_dict() to fix that:
model.query.filter_by(**request.args.to_dict()).all()

Use filter_by:
model.query.filter_by(**request.args).all()
filter is used like this: query.filter(Class.property == value) while filter_by is used like this: query.filter_by(property=value) (the first one being an expression and the latter one being a keyword argument).

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 '<class 'flask_sqlalchemy.JobSerializable'>' 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)

You can:
http://localhost:5000/filter-test?var=test
query_dict = request.args.to_dict()
print(query_dict)
{'var': 'test'}
print(query_dict['var'])
var

Related

How to use user defined python function inside a sqlalchemy query filter?

I have a function in python is_valid_id(id) which returns True or False.
I want to use this function in my sqlalchmy query inside filter condition. My query is as below.
result = session.query(tableName).filter(is_valid_id(id) == True).all()
This throwing the following error.
AttributeError: Neither 'Column' object nor 'Comparator' object has an attribute 'strip'
Can you please tell how to use a user defined function inside sqlalchemy query.
I have tried using func keyword also. That is not working.
Right now you're saying filter by (True == True).all()
This doesn't do anything.
You need to say what you're filtering.
result = session.query(tableName).filter(tableName.columnName == condition).all()
It sounds to me like you should do something like this.
Grab everything, then loop through each object and see if your id returns true.
For example:
table_objects = session.query(tableName).all()
for current_object in table_objects:
current_id = current_object.id
is_current_id_valid = is_valid_id(current_id)
if is_current_id_valid:
print(f'this id is valid: {current_id}')

I cannot make binding work with Diesel on MariaDB

I simply wanted to pass an argument to my sql query.
let query = sql("SELECT resa_comment FROM reservation WHERE resa_id = ? ");
let query2 = query.bind::<Integer, _>(1286);
let result : Result<std::vec::Vec<String>, _> = query2.load(&connection);
dbg!(result);
But the result is
[src/bin/show_posts.rs:36] result = Err(
DatabaseError(
__Unknown,
"You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near \'?\' at line 1"
)
)
The SQL query is correct because when I replace the "?" with a constant and remove the "bind", I get a correct result.
I know that I can map the table to a Rust structure but my goal is to pass complex requests with arguments so I was testing Rust and Diesel.
Is there something I missed ? Thanks.
The bind method does not replace question mark, it appends the value to the end of the query. So it should look like this:
let query = sql("SELECT resa_comment FROM reservation WHERE resa_id = ");
// ...
If you need to put value in the middle of the query, then you need to chain bind and sql calls, such as:
sql("SELECT resa_comment FROM reservation WHERE resa_id = ")
.bind::<Integer, _>(1286)
.sql(" AND something > ")
.bind::<Integer, _>(1);
But note that you should avoid writing raw sql if it is not necessary.

I got error "Unsupported lookup 'icontains ' for CharField or join on the field not permitted."

I'm trying to make a dynamic query to get data, like follwing:
query = request.GET.get('q')
kwargs = { '{0}__{1} '.format('first_name','icontains'):query}
if query:
players_list = players_list.filter(Q(**kwargs)).distinct()
then I got this error:
Unsupported lookup 'icontains ' for CharField or join on the field not permitted.
If I replaced this line
kwargs = { '{0}__{1} '.format('first_name','icontains'):query}
with this
kwargs = { 'first_name__icontains':query}
I got no errors
can anybody tell me what's the difference between them ??
You have a space before the close quote; delete it.
I had this very error. It turns out I had the "icontains" lookup twice, once explicit and a second one that I appended to every field. Removing the second lookup fixed the problem.

DRUPAL PDOException: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens

I do not know what I am doing wrong here? Can someone please help me? When the following query is executed in Drupal7 custom module, I get the following error:
ERROR:
ResponseText: PDOException: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens:
SELECT t.tid AS tid, t.name AS name
FROM
{taxonomy_term_data} t
WHERE (t.vid = :vid) AND (LOWER(t.name) LIKE LOWER('%%:last_string%%'))
LIMIT 50 OFFSET 0;
Array
(
[:vid] => 6
[:last_string] => server
)
CODE:
$result = db_select('taxonomy_term_data', 't')
->fields('t', array('tid', 'name'))
->where('t.vid = :vid', array(':vid'=>$vid))
->where("LOWER(t.name) LIKE LOWER('%%:last_string%%')", array(':last_string'=>$last_string))
->range(0, $num_results)
->execute();
The query works if I directly hard code the value for :last_string,
Example:
->where("LOWER(t.name) LIKE LOWER('%%server%%')")
any help is much appreciated..
Try using only one % because: % is a substitute for zero or more characters. You don't need 2 of them.
The LOWER function takes a string as parameter and '%:last_string%' is taken as string not as a binding to the array(':last_string'=>$last_string), that's why it works when you remove the binding. So try to not put :last_string inside the LOWER function because it won't recognize it as a binding.

Sphinx / SphinxQL - Setting weights on select

I'm using Sphinx, and I'm trying to execute the next query in mysql:
SELECT *
FROM `index_efemerides`, `index_programas`, `index_guias_para_el_aula`, `index_producciones_interactivas`
WHERE MATCH('(#(titulo,descripcion,etiquetas) nuevo)')
OPTION `field_weights` = (index_programas.titulo=100, index_programas.etiqueta=15, index_programas.descripcion=5, index_producciones_interactivas.titulo=53, index_producciones_interactivas.etiqueta=13, index_producciones_interactivas.descripcion=5, index_guias_para_el_aula.titulo=52, index_guias_para_el_aula.etiqueta=12, index_guias_para_el_aula.descripcion=5, index_efemerides.titulo=51, index_efemerides.etiqueta=11, index_efemerides.descripcion=5)
But I'm getting the next error msg:
sphinxql: syntax error, unexpected SUBKEY, expecting '=' near '.titulo=100, index_programas.etiqueta=15, index_programas.descripcion=5, index_producciones_interactivas.titulo=53, index_producciones_interactivas.etiqueta=13, index_producciones_interactivas.descripcion=5, index_guias_para_el_aula.titulo=52, index_guias_para_el_aula.etiqueta=12, index_guias_para_el_aula.descripcion=5, index_efemerides.titulo=51, index_efemerides.etiqueta=11, index_efemerides.descripcion=5)'
If I remove the dots it seems to work (not really sure because if i invent a field name, it doesn't show me any error). But i need to set the field weights different per table.
I've just found index_weight property. A possibility is to complement index_weight with field_weights like this:
SELECT * FROM `index_efemerides`, `index_programas`, `index_guias_para_el_aula`, `index_producciones_interactivas` WHERE MATCH('(#(titulo,descripcion,etiquetas) nuevo)') OPTION `field_weights` = (titulo=100, etiqueta=15, descripcion=5), `index_weights` = (index_programas=100, index_guias_para_el_aula=50, index_efemerides=75, index_producciones_interactivas=25);
Not pretty sure of the resulting weight.