Как явно заключить строковое значение в кавычки (Python DB API/Psycopg2)

StackOverflow https://stackoverflow.com/questions/309945

  •  08-07-2019
  •  | 
  •  

Вопрос

По некоторым причинам я хотел бы сделать явное цитирование строкового значения (став частью созданного SQL-запроса) вместо ожидания неявного цитирования, выполняемого cursor.execute метод по содержимому его второго параметра.

Под «неявной кавычкой» я имею в виду:

value = "Unsafe string"
query = "SELECT * FROM some_table WHERE some_char_field = %s;"
cursor.execute( query, (value,) ) # value will be correctly quoted

Я бы предпочел что-то вроде этого:

value = "Unsafe string"
query = "SELECT * FROM some_table WHERE some_char_field = %s;" % \
    READY_TO_USE_QUOTING_FUNCTION(value)
cursor.execute( query ) # value will be correctly quoted, too

Это такой низкий уровень READY_TO_USE_QUOTING_FUNCTION ожидаемое спецификацией Python DB API (я не смог найти такую ​​функциональность в ПЭП 249 документ).Если нет, то может быть, Psycopg2 предоставляет такую ​​функцию?Если нет, возможно, Django предоставляет такую ​​функцию?Я бы предпочел не писать такую ​​функцию сам...

Это было полезно?

Решение

Итак, мне было любопытно, и я пошел и посмотрел исходный код psycopg2.Оказывается, дальше папки примеров идти не пришлось :)

И да, это специфично для psycopg2.По сути, если вы просто хотите заключить в кавычки строку, вы должны сделать это:

from psycopg2.extensions import adapt

print adapt("Hello World'; DROP DATABASE World;")

Но вам, вероятно, захочется написать и зарегистрировать свой собственный адаптер;

В папке примеров psycopg2 вы найдете файл 'myfirstrecipe.py' есть пример того, как особым образом привести и цитировать определенный тип.

Если у вас есть объекты для того, что вы хотите сделать, вы можете просто создать адаптер, соответствующий протоколу IPsycopgSQLQuote (см. pydocs для примера myfirstrecipe.py... на самом деле это единственная ссылка, которую я могу найти на это имя). ), который цитирует ваш объект, а затем регистрирует его следующим образом:

from psycopg2.extensions import register_adapter

register_adapter(mytype, myadapter)

Кроме того, интересны и другие примеры;особенно 'dialtone.py' и 'простой.py'.

Другие советы

Я думаю, ты ищешь уродовать функция.

Пример:

>>> cur.mogrify("INSERT INTO test (num, data) VALUES (%s, %s)", (42, 'bar'))
"INSERT INTO test (num, data) VALUES (42, E'bar')"

Вам следует стараться избегать собственного цитирования.Как отмечали люди, это не только будет зависеть от БД, но и недостатки в цитировании являются источником ошибок SQL-инъекций.

Если вы не хотите передавать запросы и значения отдельно, передайте список параметров:

def make_my_query():
    # ...
    return sql, (value1, value2)

def do_it():
    query = make_my_query()
    cursor.execute(*query)

(Вероятно, у меня неправильный синтаксис курсора.execute.) Дело в том, что тот факт, что курсор.execute принимает несколько аргументов, не означает, что вы должны обрабатывать их все отдельно.Вы можете работать с ними как с одним списком.

Я не думаю, что вы приводите какие-либо достаточные причины, по которым вы избегаете делать это «Правильным путем».Пожалуйста, используйте API в том виде, в котором он задуман, и не старайтесь сделать ваш код менее читабельным для следующего человека и более хрупким.

Это будет зависеть от БД.Например, в случае MySQLdb connection в классе есть literal метод, который преобразует значение в правильное экранированное представление для передачи в MySQL (это то, что cursor.execute использует).

Я предполагаю, что в Postgres есть что-то подобное, но я не думаю, что в спецификации DB API 2.0 есть функция экранирования значений.

Это будет зависеть от базы данных (iirc, MySQL позволяет \ в качестве escape-символа, тогда как что-то вроде oracle ожидает удвоения кавычек: 'my '' quoted string').

Кто-нибудь поправит меня, если я ошибаюсь, но метод двойных кавычек является стандартным методом.

Возможно, стоит посмотреть, что делают другие библиотеки абстракции БД (sqlalchemy, cx_Oracle, sqlite и т. д.).

Я должен спросить: почему вы хотите встроить значения, а не привязать их?

Ваш фрагмент кода будет выглядеть примерно так, согласно документация по расширению psycopg

from psycopg2.extensions import adapt

value = "Unsafe string"
query = "SELECT * FROM some_table WHERE some_char_field = %s;" % \
    adapt(value).getquoted()
cursor.execute( query ) # value will be correctly quoted, too

А getquoted функция возвращает value как заключенную в кавычки и экранированную строку, поэтому вы также можете: "SELECT * FROM some_table WHERE some_char_field = " + adapt(value).getquoted() .

ПыПика еще один хороший вариант построения операторов SQL.Пример использования (на основе примера на главной странице проекта):

>>> from pypika import Order, Query
>>> Query.from_('customers').select('id', 'fname', 'lname', 'phone').orderby('id', order=Order.desc)
SELECT "id","fname","lname","phone" FROM "customers" ORDER BY "id" DESC

Если вы используете django, возможно, вы захотите использовать функцию цитирования, которая автоматически адаптируется к текущей настроенной СУБД:

from django.db import backend
my_quoted_variable = backend.DatabaseOperations().quote_name(myvar)
import re

def db_quote(s):
  return "\"" + re.escape(s) + "\""

может выполнять работу по простому цитированию, которая работает, по крайней мере, с MySQL.Однако что нам действительно нужно, так это функция курсора.format(), которая будет работать как курсор.execute(), за исключением того, что она будет возвращать результирующий запрос вместо его выполнения.Бывают случаи, когда вы пока не хотите, чтобы запрос выполнялся - например, вы можете сначала зарегистрировать его или распечатать для отладки, прежде чем приступить к его выполнению.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top