0

I want to execute a command using pyodbc in my Django app. When I do simple update with one column it works great:

cursor.execute("UPDATE dbo.Table SET attr = 1 WHERE id = {}".format(id))

However when I try to use a string as a column value it throws error:

cursor.execute("UPDATE dbo.Table SET attr = 1, user = '{}' WHERE id = {}".format(id, str(request.user.username)))

Here's error message:

('42S22', "[42S22] [Microsoft][ODBC SQL Server Driver][SQL Server]Invalid column name 'Admin'. (207) (SQLExecDirectW)")

Suprisingly this method works:

cursor.execute("UPDATE dbo.Table SET attr = 1, user = 'Admin' WHERE id = {}".format(id))

What seems to be the problem? Why is sql mistaking column value for its name?

2
  • 1
    highly discourage you using raw SQL like this in your django app, you're vunerable to sql injections, a bad actor could truncate and delete your entire database or worse gain access to your system without you knowing. At the least you should sanitise your input. Why aren't you using the ORM ? Commented May 28, 2021 at 14:34
  • @Umar.H I am using ORM. Raw SQL I use is necessary because database that is part of different system provides updates to one of my tables. I need to check something every time button is used and update this remote db. Also- there is no danger of someone messing with my data, this website will operate only inside my network, I will host it locally. Commented May 31, 2021 at 6:59

2 Answers 2

4

As mentioned above, you have your arguments backwards, but if you're going to use cursor.execute(), the far more important thing to do is use positional parameters (%s). This will pass the SQL and values separately to the database backend, and protect you from SQL injection:

from django.db import connection

cursor = connection.cursor()

cursor.execute("""
    UPDATE dbo.Table
    SET attr = 1,
        user = %s
    WHERE id = %s
""", [
    request.user.username,
    id,
])
Sign up to request clarification or add additional context in comments.

2 Comments

Shouldn't the %s placeholders be ? …?
@GordThompson When using a pyodbc cursor, that is true. Using it through Django, however, the placeholders are %s when using a Django cursor. Each DB engine then replaces %s to the underlying driver's placeholder: github.com/michiya/django-pyodbc-azure/blob/…
2

You've got your format arguments backwards. You're passing id to user, and username to the id WHERE clause.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.