Pregunta

Por alguna razón, me gustaría hacer una cita explícita de un valor de cadena (convirtiéndose en parte de una consulta SQL construida) en lugar de esperar una cita implícita realizada por el método cursor.execute en el contenido de su segundo parámetro.

Por " cita implícita " Quiero decir:

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

Preferiría algo así:

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

¿Es el READY_TO_USE_QUOTING_FUNCTION de bajo nivel esperado por la especificación API Python DB (no pude encontrar dicha funcionalidad en documento PEP 249 ). Si no, ¿tal vez Psycopg2 proporciona esa función? Si no, ¿tal vez Django proporciona tal función? Preferiría no escribir esa función yo mismo ...

¿Fue útil?

Solución

Ok, entonces tenía curiosidad y fui a mirar la fuente de psycopg2. Resulta que no tuve que ir más allá de la carpeta de ejemplos :)

Y sí, esto es específico de psycopg2. Básicamente, si solo desea citar una cadena, haría esto:

from psycopg2.extensions import adapt

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

Pero lo que probablemente quiera hacer es escribir y registrar su propio adaptador;

En la carpeta de ejemplos de psycopg2, encontrará el archivo 'myfirstrecipe.py' hay un ejemplo de cómo emitir y citar un tipo específico de una manera especial.

Si tiene objetos para las cosas que quiere hacer, puede crear un adaptador que se ajuste al protocolo 'IPsycopgSQLQuote' (consulte pydocs para el ejemplo myfirstrecipe.py ... en realidad esa es la única referencia que puedo encontrar a ese nombre) que cita su objeto y luego lo registra así:

from psycopg2.extensions import register_adapter

register_adapter(mytype, myadapter)

Además, los otros ejemplos son interesantes; especialmente 'dialtone.py' y 'simple.py' .

Otros consejos

Supongo que está buscando la función mogrify .

Ejemplo:

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

Debe intentar evitar hacer su propia cita. No solo será específico de DB como lo ha señalado la gente, sino que las fallas en las citas son la fuente de errores de inyección SQL.

Si no desea pasar consultas y valores por separado, pase una lista de los parámetros:

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

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

(Probablemente tengo la sintaxis de cursor.execute incorrecto) El punto aquí es que solo porque cursor.execute toma una serie de argumentos, eso no significa que tenga que manejarlos por separado. Puede tratarlos como una lista.

No creo que des un razonamiento suficiente detrás de tu evitación para hacer esto de la manera correcta. Por favor, use el APi tal como está diseñado y no intente hacer que su código sea menos legible para el próximo tipo y más frágil.

Esto dependerá de DB. En el caso de MySQLdb, por ejemplo, la clase connection tiene un método literal que convertirá el valor en la representación escapada correcta para pasar a MySQL (eso es lo que cursor.execute utiliza).

Me imagino que Postgres tiene algo similar, pero no creo que haya una función para escapar de los valores como parte de la especificación DB API 2.0.

Esto dependerá de la base de datos (iirc, mysql permite \ como un carácter de escape, mientras que algo como Oracle espera que las citas se dupliquen: 'my' 'cadena citada' ).

Alguien me corrige si estoy equivocado, pero el método de comillas dobles es el método estándar.

Puede valer la pena ver lo que hacen otras bibliotecas de abstracción db (sqlalchemy, cx_Oracle, sqlite, etc.).

Tengo que preguntar: ¿por qué desea incorporar los valores en lugar de vincularlos?

Su fragmento de código sería así, de acuerdo con documentos de extensión 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

La función getquoted devuelve el valor como una cadena entre comillas y con escape, por lo que también puede ir: " SELECT * FROM some_table WHERE some_char_field = " + adapt (value) .getquoted () .

PyPika en otra buena opción para construir sentencias SQL. Ejemplo de uso (basado en un ejemplo en la página de inicio del proyecto):

>>> 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

Si utiliza django, es posible que desee utilizar la función de presupuesto que se adapta automáticamente al DBMS configurado actualmente:

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

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

puede hacer el trabajo de una cita simple que funciona al menos con MySQL. Sin embargo, lo que realmente necesitamos es la función cursor.format () que funcionaría como cursor.execute (), excepto que devolvería la consulta resultante en lugar de ejecutarla. Hay momentos en los que no desea que la consulta se ejecute todavía, por ejemplo, es posible que desee iniciar sesión primero o imprimirla para su depuración antes de continuar con ella.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top