Pregunta

Estoy diseñando una base de datos bastante compleja, y sé que algunas de mis consultas estarán muy lejos del alcance del ORM de Django. ¿Alguien ha integrado los SP con el ORM de Django con éxito? Si es así, ¿qué RDBMS y cómo lo hiciste?

¿Fue útil?

Solución

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 desea reutilizar el código SP probado y comprobado o cuando una llamada SP será más rápida que las múltiples llamadas a la base de datos, o cuando la seguridad requiera un acceso moderado a la base de datos, o cuando las consultas sean muy complicadas / multipaso Estamos utilizando un enfoque de modelo híbrido / SP contra las bases de datos Oracle y Postgres.

El truco es facilitar su uso y mantenerlo " django " me gusta. Utilizamos una función make_instance que toma el resultado del cursor y crea instancias de un modelo rellenado desde el cursor. Esto es bueno porque el cursor podría devolver campos adicionales. Luego, puede usar esas instancias en su código / plantillas de manera muy parecida a los objetos del modelo django normal.

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

# Úsalo 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]    

saludos, Simon.

Otros consejos

Tienes que 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 obtener 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()

Si desea ver un proyecto en ejecución real que utiliza SP, consulte minibooks . Una buena cantidad de SQL personalizado y utiliza Postgres pl / pgsql para SP. Sin embargo, creo que finalmente eliminarán el SP (justificación en ticket trac 92 ).

No.

En serio.

Mueva la lógica del procedimiento almacenado a su modelo al que pertenece.

Poner algo de código en Django y algo de código en la base de datos es una pesadilla de mantenimiento. He pasado muchos de mis más de 30 años en TI tratando de limpiar este tipo de desorden.

Supongo que la compatibilidad mejorada con queryset de SQL sin formato en Django 1.2 puede hacer esto más fácil, ya que no tendría que rodar su propio código de tipo make_instance.

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