且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在Django的ORM中访问存储过程的***方式是什么?

更新时间:2023-02-17 16:23:18

我们(musicpictures.com / eviscape.com)写道,django片段,但它不是整个故事(实际上代码是只有当时在Oracle上进行测试)。



当您想重新使用经过验证的SP代码或其中一个SP调用速度比多次调用速度更快时,存储过程有意义数据库 - 或者安全性要求对数据库进行主持人的访问 - 或者查询非常复杂/多步。我们正在使用针对Oracle和Postgres数据库的混合模型/ SP方法。



诀窍是使其易于使用并保持django。我们使用一个make_instance函数来获取游标的结果,并创建一个从光标填充的模型的实例。这是很好的,因为游标可能会返回其他字段。那么你可以在代码/模板中使用这些实例,就像普通的django模型对象一样。

  def make_instance(instance,values):
'''
从eviscape.com复制

生成一个来自sp

的dict数据的实例:
实例 - 生成
值的模型的空实例 - 来自存储过程的字典,其名称类似于
模型的属性
使用像:
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())

在属性中:
try:
#来自oracle sp的字段名称是UPPER CASE
#我们要将PIC_ID放在pic_id等。
setattr(instance,a,values [a。 upper()])
del值[a.upper()]
除了:
pass

#添加任何不在模型中的值$
setattr(instance,v,values [v])
#print'将%s设置为%s'%(v,values [v])b $ b for v in values.keys

返回实例

#使用如下:

 图片= [make_instance(图片(),项目)for picture_dict] 

#这里有一些帮助函数:

  def call_an_sp ,var):
cursor = connection.cursor()
cursor.cal lproc(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

def create_dict_from_cursor(cursor):
rows = cursor.fetchall()
#DEBUG设置(用于)影响返回的内容。
如果DEBUG:
desc = [item [0] for cursor.cursor.description]
else:
desc = [item [0] for cursor.description ]
return [dict(zip(desc,item))for items in rows]

欢呼,西蒙。


I am designing a fairly complex database, and know that some of my queries will be far outside the scope of Django's ORM. Has anyone integrated SP's with Django's ORM successfully? If so, what RDBMS and how did you do it?

We (musicpictures.com / eviscape.com) wrote that django snippet but its not the whole story (actually that code was only tested on Oracle at that time).

Stored procedures make sense when you want to reuse tried and tested SP code or where one SP call will be faster than multiple calls to the database - or where security requires moderated access to the database - or where the queries are very complicated / multistep. We're using a hybrid model/SP approach against both Oracle and Postgres databases.

The trick is to make it easy to use and keep it "django" like. We use a make_instance function which takes the result of cursor and creates instances of a model populated from the cursor. This is nice because the cursor might return additional fields. Then you can use those instances in your code / templates much like normal django model objects.

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

# Use it like this:

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

# And here are some helper functions:

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]    

cheers, Simon.