Django의 ORM에서 저장된 절차에 액세스하는 가장 좋은 방법은 무엇입니까?
-
03-07-2019 - |
문제
나는 상당히 복잡한 데이터베이스를 설계하고 있으며, 일부 쿼리는 Django의 ORM의 범위를 훨씬 벗어날 것임을 알고 있습니다. Django의 ORM과 SP를 통합 한 사람이 있습니까? 그렇다면 어떤 RDBMS와 어떻게 했습니까?
해결책
우리 (Musicpictures.com / eviscape.com)는 Django 스 니펫을 썼지 만 전체 스토리는 아니라고 썼습니다 (실제로 그 코드는 그 당시 Oracle에서만 테스트되었습니다).
저장된 절차는 시도 및 테스트 된 SP 코드를 재사용하려고하거나 하나의 SP 호출이 데이터베이스에 대한 여러 통화보다 빠르거나 보안이 데이터베이스에 대한 조정 된 액세스가 필요한 경우 또는 쿼리가 매우 복잡한 / 멀티 스펙트 인 경우에 적합합니다. 우리는 Oracle 및 Postgres 데이터베이스에 대한 하이브리드 모델/SP 접근법을 사용하고 있습니다.
요령은 사용하기 쉽고 "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'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]
건배, 사이먼.
다른 팁
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/
좋은 예가 있습니다. 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()
하지 않다.
진지하게.
저장된 프로 시저 로직을 모델로 이동하십시오.
Django에 일부 코드를 넣고 데이터베이스에 일부 코드를 넣는 것은 유지 보수 악몽입니다. 나는 이런 종류의 혼란을 정리하려고 30 년 이상을 너무 많이 보냈다.
Django 1.2의 개선 된 원시 SQL 쿼리 세트 지원이 자신의 make_instance 유형 코드를 롤링 할 필요가 없으므로 더 쉽게 만들 수 있다고 생각합니다.