python - raw - Cuál es la mejor forma de acceder a los procedimientos almacenados en el ORM de Django
django raw query (6)
Estoy diseñando una base de datos bastante compleja y sé que algunas de mis consultas quedarán fuera del alcance del ORM de Django. ¿Alguien ha integrado SP con el ORM de Django con éxito? Si es así, ¿qué RDBMS y cómo lo hiciste?
Debes usar la utilidad de conexión en Django:
from django.db import connection
cursor = connection.cursor()
cursor.execute("SQL STATEMENT CAN BE ANYTHING")
entonces puedes buscar los datos:
cursor.fetchone()
o:
cursor.fetchall()
Más información aquí: http://docs.djangoproject.com/en/dev/topics/db/sql/
Hay un buen ejemplo: https://djangosnippets.org/snippets/118/
from django.db import connection
cursor = connection.cursor()
ret = cursor.callproc("MY_UTIL.LOG_MESSAGE", (control_in, message_in))# calls PROCEDURE named LOG_MESSAGE which resides in MY_UTIL Package
cursor.close()
No lo hagas
Seriamente.
Mueva la lógica del procedimiento almacenado a su modelo donde pertenece.
Poner código en Django y algún código en la base de datos es una pesadilla de mantenimiento. He pasado demasiados de mis más de 30 años en TI tratando de limpiar este tipo de desorden.
Nosotros (musicpictures.com / eviscape.com) escribimos ese fragmento de django, pero no es toda la historia (en realidad, ese código solo se probó en Oracle en ese momento).
Los procedimientos almacenados tienen sentido cuando se quiere reutilizar un código SP probado o donde una llamada SP será más rápida que múltiples llamadas a la base de datos, o donde la seguridad requiere acceso moderado a la base de datos, o donde las consultas son muy complicadas / multipaso. Estamos utilizando un enfoque de modelo híbrido / SP frente a las bases de datos Oracle y Postgres.
El truco es hacer que sea fácil de usar y mantenerlo como "django". Utilizamos una función make_instance que toma el resultado del cursor y crea instancias de un modelo poblado por el cursor. Esto es bueno porque el cursor puede devolver campos adicionales. Entonces puede usar esas instancias en su código / plantillas al igual que los objetos normales del modelo django.
def make_instance(instance, values):
''''''
Copied from eviscape.com
generates an instance for dict data coming from an sp
expects:
instance - empty instance of the model to generate
values - dictionary from a stored procedure with keys that are named like the
model''s attributes
use like:
evis = InstanceGenerator(Evis(), evis_dict_from_SP)
>>> make_instance(Evis(), {''evi_id'': ''007'', ''evi_subject'': ''J. Bond, Architect''})
<Evis: J. Bond, Architect>
''''''
attributes = filter(lambda x: not x.startswith(''_''), instance.__dict__.keys())
for a in attributes:
try:
# field names from oracle sp are UPPER CASE
# we want to put PIC_ID in pic_id etc.
setattr(instance, a, values[a.upper()])
del values[a.upper()]
except:
pass
#add any values that are not in the model as well
for v in values.keys():
setattr(instance, v, values[v])
#print ''setting %s to %s'' % (v, values[v])
return instance
# Úselo así:
pictures = [make_instance(Pictures(), item) for item in picture_dict]
# Y aquí hay algunas funciones de ayuda:
def call_an_sp(self, var):
cursor = connection.cursor()
cursor.callproc("fn_sp_name", (var,))
return self.fn_generic(cursor)
def fn_generic(self, cursor):
msg = cursor.fetchone()[0]
cursor.execute(''FETCH ALL IN "%s"'' % msg)
thing = create_dict_from_cursor(cursor)
cursor.close()
return thing
def create_dict_from_cursor(cursor):
rows = cursor.fetchall()
# DEBUG settings (used to) affect what gets returned.
if DEBUG:
desc = [item[0] for item in cursor.cursor.description]
else:
desc = [item[0] for item in cursor.description]
return [dict(zip(desc, item)) for item in rows]
Salud, Simon.
Supongo que el soporte de SQL Server mejorado mejorado en Django 1.2 puede hacer esto más fácil ya que no tendrías que lanzar tu propio código de tipo make_instance.