30π
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.
22π
You have to use the connection utility in Django:
from django.db import connection
with connection.cursor() as cursor:
cursor.execute("SQL STATEMENT CAN BE ANYTHING")
data = cursor.fetchone()
If you are expecting more than one row, use cursor.fetchall()
to fetch a list of them.
More info here: http://docs.djangoproject.com/en/dev/topics/db/sql/
- [Django]-How can I make a Django form field contain only alphanumeric characters
- [Django]-Django get a QuerySet from array of id's in specific order
- [Django]-Adding to the "constructor" of a django model
6π
Donβt.
Seriously.
Move the stored procedure logic into your model where it belongs.
Putting some code in Django and some code in the database is a maintenance nightmare. Iβve spent too many of my 30+ years in IT trying to clean up this kind of mess.
- [Django]-Django equivalent of SQL not in
- [Django]-Django model fields validation
- [Django]-Can I have a Django form without Model
5π
There is a good example :
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]-Redis Python β how to delete all keys according to a specific pattern In python, without python iterating
- [Django]-How to query directly the table created by Django for a ManyToMany relation?
- [Django]-Copy a database column into another in Django
2π
If you want to look at an actual running project that uses SP, check out minibooks. A good deal of custom SQL and uses Postgres pl/pgsql for SP. I think theyβre going to remove the SP eventually though (justification in trac ticket 92).
- [Django]-Django REST Framework (DRF): Set current user id as field value
- [Django]-Can "list_display" in a Django ModelAdmin display attributes of ForeignKey fields?
- [Django]-How to make Facebook Login possible in Django app ?
0π
I guess the improved raw sql queryset support in Django 1.2 can make this easier as you wouldnβt have to roll your own make_instance type code.
- [Django]-Reducing Django Memory Usage. Low hanging fruit?
- [Django]-Which Model Field to use in Django to store longitude and latitude values?
- [Django]-Django post_save signals on update
0π
Cx_Oracle can be used. Also, It is fairly helpful when we do not have access to production deployed code and need arises to make major changes in database.
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)
- [Django]-"Models aren't loaded yet" error while populating in Django 1.8 or later
- [Django]-Django rest framework: query parameters in detail_route
- [Django]-What is the difference render() and redirect() in Django?