Domanda

Sto progettando un database abbastanza complesso e so che alcune delle mie query saranno molto al di fuori dell'ambito dell'ORM di Django. Qualcuno ha integrato con successo gli SP con l'ORM di Django? In tal caso, quale RDBMS e come hai fatto?

È stato utile?

Soluzione

Noi (musicpictures.com / eviscape.com) abbiamo scritto quel frammento di django ma non è l'intera storia (in realtà quel codice è stato testato solo su Oracle in quel momento).

Le procedure memorizzate hanno senso quando si desidera riutilizzare il codice SP provato e testato o dove una chiamata SP sarà più veloce di più chiamate al database - o dove la sicurezza richiede un accesso moderato al database - o dove le query sono molto complicate / fasi. Stiamo usando un modello ibrido / approccio SP contro database Oracle e Postgres.

Il trucco è renderlo facile da usare e tenerlo " django " piace. Usiamo una funzione make_instance che prende il risultato del cursore e crea istanze di un modello popolato dal cursore. Questo è utile perché il cursore potrebbe restituire campi aggiuntivi. Quindi puoi usare quelle istanze nel tuo codice / template in modo simile ai normali oggetti modello 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

# Usalo in questo modo:

pictures = [make_instance(Pictures(), item) for item in picture_dict]

# Ed ecco alcune funzioni di aiuto:

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]    

evviva, Simon.

Altri suggerimenti

Devi usare l'utilità di connessione in Django:

from django.db import connection

cursor = connection.cursor()
cursor.execute("SQL STATEMENT CAN BE ANYTHING")

quindi puoi recuperare i dati:

cursor.fetchone()

o

cursor.fetchall()

Maggiori informazioni qui: http://docs.djangoproject.com/en / dev / argomenti / db / sql /

C'è un buon esempio:   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()

Se vuoi guardare un vero progetto in esecuzione che utilizza SP, controlla minibooks . Buona parte dell'SQL personalizzato e utilizza Postgres pl / pgsql per SP. Penso che alla fine rimuoveranno l'SP (giustificazione in trac ticket 92 ).

Non farlo.

Scherzi a parte.

Sposta la logica della procedura memorizzata nel modello a cui appartiene.

Inserire un po 'di codice in Django e un po' di codice nel database è un incubo per la manutenzione. Ho trascorso troppi dei miei oltre 30 anni in IT cercando di ripulire questo tipo di pasticcio.

Suppongo che il supporto del queryset sql migliorato in Django 1.2 possa renderlo più semplice in quanto non dovresti creare il tuo codice di tipo make_instance.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top