Escaping queries in Django - django

I have the following method:
def select_query(self):
sql = "SELECT * FROM {t} WHERE 1".format(t=self._meta.db_table)
for column_name in self.distinguishing_column_names():
sql = sql + " AND {c} = {v}".format(c=column_name, v=getattr(self, column_name))
return sql
This will give me a query like this:
SELECT * FROM customer WHERE 1 AND name = JOHN SMITH AND customer_number = 11423 AND social_security_number = 1234567890 AND phone = 2323523353
Obviously, that's not going to work. Is there a way to get Django to quote this for me?
Note: I'm not asking for a prepared statement. That's something different.

Do you need to return a query this way? The proper way would be to call cursor with the query and the params as argument:
Does Python support MySQL prepared statements?
The correct way to format a query seems to be:
query = query % db.literal(args)
Where db is a mysql.Connection (or presumably any connection)

Apparently the answer is "no."

Related

Express the raw sql into Django notation object filter

Is there any way to express the following raw sql into django notation with filter ?
for p in wm.user_visibility.objects.raw('SELECT * FROM user S
LEFT JOIN user_visibility SA
ON S.Id = SA.user_id AND SA.dash_id=' + param +
'WHERE SA.user_id IS NULL'):
print(p.full_name)
user_visibility.objects.filter(dash_id = param, user_id__isnull = True)
P.s.
Your SQL is weird. Joining user and user_visibility on user_id, but then keep only entries where user_visibility.user_id is null.

SqlAlchemy core union_all not adding parentheses

I have the following sample code:
queries = []
q1 = select([columns]).where(table.c.id == #).limit(#)
queries.append(q1)
q2 = select([columns]).where(table.c.id == #).limit(#)
queries.append(q2)
final_query = union_all(*queries)
The generated SQL should be this:
(select columns from table where id = # limit #)
UNION ALL
(select columns from table where id = # limit #)
But, I'm getting
select columns from table where id = # limit #
UNION ALL
select columns from table where id = # limit #
I tried using subquery, as follows for my queries:
q1 = subquery(select([columns]).where(table.c.id == #).limit(#))
The generated query then looks like this:
SELECT UNION ALL SELECT UNION ALL
I also tried doing
q1 = select([columns]).where(table.c.id == #).limit(#)).subquery()
But, I get the error:
'Select' object has no attribute 'subquery'
Any help to get the desired output with my subqueries wrapped in parentheses?
Note: this is not a duplicate of this question, because I'm not using Session.
EDIT
Okay, this works, but I don't believe it is very efficient, and it's adding an extra select * from (my sub query), but it works.
q1 = select('*').select_from((select(columns).where(table.c.id == #).limit(#)).alias('q1'))
So, if anyone has any ideas to optimize, or let me know if this is as good as it gets. I would appreciate it.
The author of SQLAlchemy seems to be aware of this and mentions a workaround for it on the SQLAlchemy 1.1 changelog page. The general idea is to do .alias().select() on each select.
stmt1 = select([table1.c.x]).order_by(table1.c.y).limit(1).alias().select()
stmt2 = select([table2.c.x]).order_by(table2.c.y).limit(2).alias().select()
stmt = union(stmt1, stmt2)

Django raw Query aggreation function

I need to write django raw query function to get the sum value and then write to the csn file.
I write my query
for time in Tracking_details.objects.raw('SELECT *,sum=SUM(work_time) FROM structure_tracking_details WHERE employee_id='+ employee_id + ' GROUP BY project_structure ') :
writer.writerow([ time.project_structure,time.sum ])
it tells
no such column: sum
How do I write the query correctly?
Replace sum=SUM(work_time) with SUM(work_time) AS sum.
BTW, employee_id='+ employee_id + ' is a very poor way of building queries. And you should not do it. It makes your query prone to SQL Injection as Django doesn't check whatever query you pass in raw() function. You can pass parameters to the raw query like this -
Tracking_details.objects.raw('SELECT *, SUM(work_time) AS sum FROM structure_tracking_details WHERE employee_id = %s GROUP BY project_structure', [employee_id])
More details.

How to django ORM with a subquery?

The sql subquery is:
SELECT *
FROM ( SELECT *
FROM article
ORDER BY Fid desc
LIMIT 0, 200
) as l
WHERE keyId = 1
AND typeId = 0
I tried this:
rets = Article.objects.order_by("-Fid").values('Fid')
kwargs['keyId'] = 1
kwargs['typeId'] = 0
re = Article.objects.filter(Fid__in=rets).filter(**kwargs).values()
But it's not working. Can anyone explain how I can do this?
In your case I guess you can resort to raw SQL (untested). Note that using raw SQL you have to know the real table and column names (just test the statement directly on the database first, to see if it flies).
For example:
Article.objects.raw("""SELECT * from (
SELECT * FROM yourapp_article
ORDER BY fid DESC
LIMIT 0, 200
) AS q1 WHERE key_id=1 AND type_id=0""")
[update]
wuent wrtote:
thanks for your help. But the raw SQL is not my wanted. I need keep my program orm style. – wuent
If you are used to more powerful/consistent ORMs like SQLAlchemy or even peewee, give up your hope. The Django ORM has a very crippled design and AFAIK you can't do this kind of thing using it - the first version of this answer started with a rant about this.
Looking at your query again, I got the impression that you do not need a subquery, try querying the table directly - my guess is the result will be the same.
How about this?
rets = Article.objects.order_by("-Fid").values_list('Fid', flat=True)
kwargs['keyId'] = 1
kwargs['typeId'] = 0
re = Article.objects.filter(Fid__in=rets).filter(**kwargs).values()

psycopg2 strange behavior

from django.db import connection
q = 'some value'
sql1 = 'SELECT * FROM table WHERE field LIKE %%%s%%' % q
sql2 = 'SELECT * FROM table WHERE field LIKE %%'+ q +'%%'
cursor = connection.cursor()
cursor.execute( sql1 ) #why exception: IndexError: tuple index out of range ?
cursor.execute( sql2 ) #works ok
You need to QUOTE properly your SQL arguments.
And by quoting properly I mean using the quote facility provided by DBAPI, not adding a ' around your string, which is useless.
Correct code :
q = "%"+q+"%"
cursor.execute( 'SELECT * FROM table WHERE field LIKE %s', (q,) )
Really correct code :
q = "%"+q.replace("%","%%")+"%"
cursor.execute( 'SELECT * FROM table WHERE field LIKE %s', (q,) )
Suppose q = "a'bc"
First, rewrite this as "%a'bc%"
Then use it as a normal string argument. psycopg will rewrite it as '%a\'bc%' as it should.
If q may contain "%" and you want to search for it, then use the second one.
Using direct string manipulation will almost certainly lead to improper SQL that is vulnerable to SQL Injection attacks (see psycopg2's comments on the subject).
What I think you're looking to do is try and perform a LIKE '%some value%' in django, right?:
from django.db import connection
q = '%some value%'
cur = connection.cursor()
cur.execute("SELECT * FROM table WHERE field LIKE %(my_like)s", {'my_like': q})
As of psycopg2 2.4.1, the SQL that is executed on the server is:
SELECT * FROM table WHERE field LIKE '%some value%'
You need to QUOTE properly your SQL command:
sql1 = "SELECT * FROM table WHERE field LIKE '%%%s%%'" % q
sql2 = "SELECT * FROM table WHERE field LIKE '%"+ q +"%'"
And by quoting properly I mean using single quotes with LIKE expressions.