How to print query of Django ORM - mysql

I am using Django ORM query with Extra params. when I try to print the SQL query relevant to that ORM Query,i am getting the below Error message.
ORM Query:
Record = SAMPLE_TABLE.objects.extra(where=["REPLACE(Message,' ','') "+whereCaseSensitive+" like %s "+query],params=[duplicateCheckMessage]).filter(~Q(iStatus=2),~Q(iAppStatus=2),iEntityID=entityId,iTemplateType=1).first()
Message - FieldName ,
whereCaseSensitive - '',
query - ( FIND_IN_SET("test",Testfield))
I am trying to fetch the sql query related to this using
print(Record.query)
when i run this i am getting Exception as 'NoneType' object has no attribute 'query'
Can any one help on this ?

You can't print the query for the first (or any) element of a queryset because it is an instance, not a query. To print .query you need to do it on the queryset
Try this
my_query = SAMPLE_TABLE.objects.extra(*some_extra).filter(*some_filter)
print(my_query.query)
record = my_query.first()

Related

Hash a Select SQLAlchemy query

I have a SQLAlchemy query that I build, such as :
query_one = User.query.filter(User.id == 1) # Note that I don't call .first() or .all() as I want the "select" instance.
I want to store this Select query in such a way that I can retrieve it by having the same query :
stored_queries = {}
stored_queries[hash(query_one)] = query_one
# ... later on:
query_two = User.query.filter(User.id == 1)
if hash(query_two) in stored_queries:
# Execute custom code because it's the same query
Of course, hash in that case does not work, but is there a SQLAlchemy method that works in the same way?
I thought of str(query_one), but that query only consider the request, without the value. I need both.
Thank you in advance.
You can compile the query to get access to the parameters, and use those as part of your key:
def query_key(query):
statement = query_one.statement.compile()
return str(statement), str(statement.params)
query_key(query_one)
('SELECT user.id, ... FROM user WHERE user.id = :id_1', "{'id_1': 1}")
See https://docs.sqlalchemy.org/en/14/core/selectable.html#sqlalchemy.sql.expression.TableClause.compile

MySQL - Query has to many arguments when select with variable

I am switching from SQLite to MySQL and getting some problems with my Queries. At the moment i am trying to SELECT from a Table where the PackageName is like a variable from a Text Input in my GUI.
The Query looks like this:
test = self.ms.ExecQuery("SELECT PackageID,PackageName,ServiceFee,Cost,LatestChanges FROM Package WHERE PackageName=?", (self.search_entry.GetValue(),))
and my ExecQuery looks like this:
def ExecQuery(self, sql):
cur = self._Getconnect()
cur.execute(sql)
relist = cur.fetchall()
cur.close()
self.conn.close()
return relist
And the error i am getting:
TypeError: ExecQuery() takes 2 positional arguments but 3 were given
What do i need to change to get this running?
You have sql as the 2nd parameter in your ExecQuery, yet you are passing in a sql query as the 1st parameter:
test = self.ms.ExecQuery("SELECT PackageID,PackageName,ServiceFee,Cost,LatestChanges FROM Package WHERE PackageName=?", (self.search_entry.GetValue(),))

How to use from_statement with pagination in SQLalchemy?

I have a complex query sql = "SELECT title, name, country FROM ...", which I execute using
results = db.session.query("title", "name", "country").from_statement(text(sql)).all()
This works and produces the desired results. I would like to paginate this query, but
results = db.session.query("title", "name", "country").from_statement(text(sql)).paginate(1,10, False)
gives me the error AttributeError: 'Query' object has no attribute 'paginate'. I have successfully used paginate() elsewhere in my code, but never with the from_statement(). How can I do this?

Flask - Convert request.args to dict

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

Django: raw SQL queries with a dynamic number of variables

Is it possible to construct raw SQL queries in Django so that they accept a dynamic number of arguments? So for example say that I have the following url structure in my app:
/books/category/history/
/books/category/history/1800s/
For the first query, I'm looking for all books with the keyword 'history', and for the second, I'm looking for all books with the keyword 'history' AND the keyword '1800s'.
I currently have two separate queries for each of these:
keyword1 = 'history'
SELECT appname_book.name AS name FROM appname_book WHERE keyword=%s,[keyword1]
keyword1 = 'history'
keyword2 = '1800s'
SELECT appname_book.name AS name FROM appname_book WHERE keyword=%s AND keyword=%s,[keyword1, keyword2]
Anyone know of a cleaner and more efficient way to do this?
I'm using Django 1.3 and MySQL.
Thanks.
Why dont you use Django QuerySet, like this:
Book.objects.all().filter(keyword__in=['history','1800s']).values('name')
Another possible solution using RAW SQL, coud be:
keywords = []
SQL = 'SELECT appname_book.name AS name FROM appname_book WHERE 1=1 '
SQL += ' '.join(['AND keyword=%s' for _ in params])
Sure, you could do something like this to dynamically generate a raw SQL query
sql = 'SELECT id FROM table WHERE 1 = 1'
params = []
if 'description' in args.keys():
sql += ' AND description LIKE %s'
params.append('%'+args['description']+'%')
if 'is_active' in args.keys():
sql += ' AND is_active LIKE %s'
params.append(args['is_active'])
... you can put as many "ifs" you want to construct the query
with connections['default'].cursor() as cursor:
cursor.execute(sql, params)
This way would still be completely safe against SQL Injections vulnerability