Question

Je conçois une base de données assez complexe et je sais que certaines de mes requêtes dépasseront de loin les possibilités de ORM de Django. Quelqu'un at-il intégré les OR avec Django's ORM avec succès? Si oui, quel SGBDR et comment l'avez-vous fait?

Était-ce utile?

La solution

Nous (musicpictures.com / eviscape.com) avons écrit cet extrait de django, mais ce n’est pas toute l’histoire (en réalité, ce code n’a été testé que sur Oracle à ce moment-là).

Les procédures stockées ont du sens si vous souhaitez réutiliser un code SP éprouvé ou si un appel SP est plus rapide que plusieurs appels à la base de données - ou lorsque la sécurité nécessite un accès modéré à la base de données - ou lorsque les requêtes sont très compliquées / plusieurs étapes. Nous utilisons une approche modèle / SP hybride pour les bases de données Oracle et Postgres.

Le truc, c'est de le rendre facile à utiliser et à le conserver "django". comme. Nous utilisons une fonction make_instance qui prend le résultat du curseur et crée des instances d'un modèle rempli à partir du curseur. C'est bien parce que le curseur peut retourner des champs supplémentaires. Vous pouvez ensuite utiliser ces instances dans votre code / modèle de la même manière que les objets modèles django normaux.

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

# Utilisez-le comme ceci:

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

# Et voici quelques fonctions d'aide:

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]    

Bravo, Simon.

Autres conseils

Vous devez utiliser l'utilitaire de connexion dans Django:

from django.db import connection

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

alors vous pouvez récupérer les données:

cursor.fetchone()

ou:

cursor.fetchall()

Plus d'infos ici: http://docs.djangoproject.com/fr / dev / topics / db / sql /

Voici un bon exemple:   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 vous souhaitez consulter un projet en cours d'exécution utilisant SP, consultez minibooks . Beaucoup de SQL personnalisé et utilise Postgres pl / pgsql pour SP. Je pense qu’ils finiront par retirer le SP (justification dans billet trac 92 ).

Ne pas.

Sérieusement.

Déplacez la logique de procédure stockée dans votre modèle auquel elle appartient.

Mettre du code dans Django et du code dans la base de données est un cauchemar de maintenance. J'ai passé trop de temps dans l'informatique pendant plus de 30 ans à essayer de nettoyer ce genre de désordre.

Je suppose que la prise en charge améliorée des requêtes SQL brutes dans Django 1.2 peut faciliter la tâche, car vous n'avez pas à lancer votre propre code de type make_instance.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top