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

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


person kkubasik    schedule 30.04.2009    source источник
comment
Django с использованием хранимой процедуры даст некоторое представление.   -  person Dhanapal    schedule 30.04.2009


Ответы (7)


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

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

Хитрость заключается в том, чтобы сделать его простым в использовании и сохранить его как «джанго». Мы используем функцию 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'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

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

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]    

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

person Community    schedule 04.05.2009
comment
Почему вы закрываете курсор в fn_generic? - person Joe Holloway; 13.10.2011
comment
Я работаю над огромной системой с базой данных, к которой обращаются несколько приложений, некоторые из которых основаны на С++, некоторые на Python, некоторые на Perl, некоторые на php, некоторые на веб-сайтах, многие нет. Мне нравится, когда бизнес-логика находится в SP, потому что это означает, что логика согласуется во всех реализациях и, по крайней мере, в нашем случае, значительно упрощает обслуживание. - person compound eye; 08.11.2011
comment
я нашел этот комментарий Расса Маги: Мы специально избегали добавления очевидных SQL-подобных функций в Django ORM, потому что, в конце концов, мы не пытаемся заменить SQL - мы просто пытаемся предоставить удобный способ выражать простые запросы. Полностью ожидается, что вы вернетесь к простому вызову необработанного SQL для сложных случаев. - person compound eye; 10.11.2011

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

from django.db import connection

with connection.cursor() as cursor:
    cursor.execute("SQL STATEMENT CAN BE ANYTHING")
    data = cursor.fetchone()

Если вы ожидаете более одной строки, используйте cursor.fetchall() для получения их списка.

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

person igorgue    schedule 30.04.2009

Не.

Шутки в сторону.

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

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

person S.Lott    schedule 30.04.2009
comment
Он спрашивает об интеграции ORM с SP. Это, вероятно, невозможно, и использование хранимых процедур, вероятно, требует, чтобы вы просто обращались к django.db.connection напрямую, как в других ответах, но было бы интересно, если бы вы могли автоматически перемещать общие запросы, которые ORM делает в хранимые процедуры, чтобы сохранить на время генерации запроса, и делать это прозрачно, как оптимизацию. Это не будет работать на каждой базе данных, и прирост производительности, вероятно, не стоит того, но было бы интересно исследовать. - person Chad; 11.05.2011
comment
@Chad: Он спрашивает об интеграции ORM с SP. Понял. Отсюда мой ответ. SP фрагментирует логику вашего приложения между правильным кодом приложения и базой данных. Часто они создают больше проблем, чем решают. Я думаю, что SP бесполезны ни при каких обстоятельствах и не должны использоваться. - person S.Lott; 11.05.2011
comment
@S.Lott Я думаю, вы неправильно поняли мою мысль. Я говорю о воображаемом/будущем Django ORM. Хранимые процедуры не будут написаны разработчиками. Этот ORM будет динамически/прозрачно преобразовывать обычно выполняемые запросы ORM в хранимые процедуры, чтобы сэкономить время генерации строки SQL и использовать предварительно скомпилированный характер SP. Опять же, я не утверждаю, что это вообще возможно или что это стоило бы ускорения. Просто указал на интересную идею, которую его вопрос породил для меня. Такой подход может оставить всю логику в коде и обеспечить производительность SP. - person Chad; 18.05.2011
comment
@Chad: Я думаю, ты неправильно понял мою мысль. Я говорю обо всех SP как об одинаково плохой идее. Это не интересно. Это ошибка. SP не создают волшебным образом высокую производительность. - person S.Lott; 18.05.2011
comment
@С. Лотт, это не волшебство. Быстрее сгенерировать EXEC some_sp_name(with, params), чем сгенерировать большой оператор SQL. Вы можете сказать, что это просто струны, это очень быстро. Да, но если вы разобрались с генерацией ORM SQL django, я думаю, вы бы увидели, что это немного более пугающе, чем это. Кроме того, хранимые процедуры используют преимущества предварительно скомпилированного SQL, как параметризованный запрос. Я согласен, что хранимые процедуры полный отстой, но вы должны признать, что это интересная идея, чтобы ORM прозрачно генерировал их для вас вместо того, чтобы каждый раз генерировать SQL. - person Chad; 20.05.2011
comment
@Chad: я говорю обо всех SP как о плохой идее. Равномерно. Общий. Код теперь находится в двух местах. Кажется, что в долгосрочной перспективе такая фрагментация кода никогда не сработает. - person S.Lott; 20.05.2011
comment
@ S.Lott Итак, через 30 лет вы можете сказать, что равномерно и в целом хранимые процедуры - плохая идея? Вау, это охватывает множество случаев, и я не покупаюсь на это ни на секунду. Есть много случаев, и я не могу представить, что вы лично можете засвидетельствовать их все. Просто мои 2cents. Я могу придумать много случаев, когда они имеют ИДЕАЛЬНЫЙ смысл, и другие случаи, когда это не так. Просто для протокола: в некоторых случаях, которые я могу вообразить или над которыми работал, я полностью согласен с вами, а в других я нахожусь на другой стороне вселенной с вашей точки зрения. - person Kuberchaun; 08.03.2012
comment
@ S.Lott, ты все еще не понимаешь, что я пытался сказать. Код по-прежнему находится в ОДНОМ месте. Весь код существует только в логике ORM в Python. Хранимые процедуры, о которых я говорю, написаны не программистом. Когда ORM замечает, что определенный точный запрос отправляется много, в качестве микрооптимизации ORM динамически создает новую хранимую процедуру и использует ее вместо того, чтобы каждый раз генерировать SQL. Нет фрагментации кода! Разработчики только пишут код Python, и все преимущества SP получаются прозрачно, без необходимости писать какие-либо SP или фрагментировать вашу бизнес-логику. - person Chad; 21.03.2012

Хороший пример: 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()
person Hemant    schedule 25.06.2015

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

person Van Gale    schedule 30.04.2009

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

person Anentropic    schedule 09.09.2010

Можно использовать Cx_Oracle. Кроме того, это довольно полезно, когда у нас нет доступа к производственному развернутому коду и возникает необходимость внести серьезные изменения в базу данных.

import cx_Oracle
try:
    db = dev_plng_con
    con = cx_Oracle.connect(db)
    cur = con.cursor()
    P_ERROR = str(error)
    cur.callproc('NAME_OF_PACKAGE.PROCEDURENAME', [P_ERROR])

except Exception as error:
    error_logger.error(message)
person Yash Yennam    schedule 13.11.2019