Подтвердить что ты не робот

Каков наилучший способ доступа к хранимым процедурам в Django ORM

Я разрабатываю довольно сложную базу данных и знаю, что некоторые из моих запросов будут далеко за пределами Django ORM. Кто-нибудь интегрировал SP с Django ORM успешно? Если да, то какая СУБД и как вы это сделали?

4b9b3361

Ответ 1

Мы (musicpictures.com/eviscape.com) писали, что django snippet, но его не вся история (на самом деле этот код тестировался только на Oracle в то время).

Сохраненные процедуры имеют смысл, если вы хотите повторно использовать проверенный и протестированный SP-код или когда один вызов SP будет быстрее, чем несколько вызовов в базе данных - или где требуется безопасность, требуется умеренный доступ к базе данных - или где запросы очень сложны/многоступенчатый. Мы используем гибридную модель/SP-подход к базам данных Oracle и Postgres.

Трюк заключается в том, чтобы сделать его простым в использовании и сохранить его как "django". Мы используем функцию make_instance, которая берет результат курсора и создает экземпляры модели, заполненной курсором. Это хорошо, потому что курсор может возвращать дополнительные поля. Затем вы можете использовать эти экземпляры в вашем коде/шаблонах, как обычные объекты модели 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 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

# Используйте его так:

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

# И вот некоторые вспомогательные функции:

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]    

приветствия, Саймон.

Ответ 2

Вы должны использовать утилиту подключения в Django:

from django.db import connection

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

то вы можете получить данные:

cursor.fetchone()

или

cursor.fetchall()

Дополнительная информация здесь: http://docs.djangoproject.com/en/dev/topics/db/sql/

Ответ 3

Есть хороший пример:  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()

Ответ 4

Если вы хотите посмотреть фактический запущенный проект, который использует SP, посмотрите minibooks. Большое количество пользовательских SQL и использует Postgres pl/pgsql для SP. Я думаю, что они собираются удалить SP в конечном итоге (обоснование в trac ticket 92).

Ответ 5

Я предполагаю, что улучшенная поддержка запросов sql sql в Django 1.2 может сделать это проще, так как вам не нужно будет сворачивать свой собственный код типа make_instance.

Ответ 6

Не.

Серьезно.

Переместите логику хранимой процедуры в свою модель, где она принадлежит.

Помещение некоторого кода в Django, а некоторый код в базе данных - кошмар обслуживания. Я потратил слишком много моих 30 лет на ИТ, пытаясь убрать этот беспорядок.