Django - Stored procedure does not exist - python

I trying call stored procedure in Django, but this showed this message (1305, 'PROCEDURE storedprocedureservice.MyStoredProcedure does not exist')
This is my code:
class StoredProcedureService():
def close_service(self, param1, param2, param3):
cursor = connection.cursor()
ret = cursor.callproc("StoredProcedureService.MyStoredProcedure", (self, param1, param2, param3))
cursor.close()
return ret
#csrf_exempt
def service(request):
if request.is_ajax:
value = request.POST.get('value')
stored_procedure = StoredProcedureService()
ret = stored_procedure.close_service(value, 1, 'Lorem Ipsum')
return JsonResponse({"status":"ok"})
My procedure is in other database, I ready configure it, but don't know how call it.
I try it, but not working:
cursor = connection.using("myOtherDatabase").cursor()

I resolved my question thanks this answer https://stackoverflow.com/a/28029109/3464573
My code was this way:
class StoredProcedureService():
def close_service(self, param1, param2, param3):
cursor = connections["mydatabase"].cursor()
cursor.callproc("StoredProcedureService.MyStoredProcedure", [param1, param2, param3])
results = cursor.fetchall()
cursor.close()
return results
#csrf_exempt
def service(request):
if request.is_ajax:
value = request.POST.get('value')
stored_procedure = StoredProcedureService()
ret = stored_procedure.close_service(value, 1, 'Lorem Ipsum')
return JsonResponse({"status":"ok"})

Related

create db.connection custom class wrapper, keep getting "django.db.utils.InterfaceError: cursor already closed"

im trying to make custom class wrapper for "django.db.connection",
but im keep getting "django.db.utils.InterfaceError: cursor already closed".
the working code is something like this if without custom class wrapper (copied from ./manage.py shell) :
>>> from django.db import (connection as con)
>>> with con.cursor() as q:
... q.execute('select * from master.years a where a.years = %s', [str(2019)])
... f = [f.name for f in q.description]
... for b in q:
... print(dict(zip(f,b)))
my wrapper webapp/mine/db.py :
class query_00:
def __init__(self, db_con, db_sql, db_stmt = []):
self.db_con = db_con
self.db_sql = db_sql
self.fields = []
with db_con.cursor() as self.query:
self.query.execute(db_sql, db_stmt)
self.fields = [f.name for f in self.query.description]
# for entry in self.query:
# yield dict(zip(self.fields, entry))
# self.query = db_con.cursor()
# must return self, because
# AttributeError: 'NoneType' object has no attribute 'result'
def __enter__(self):
return self
# self.query.execute(self.db_sql, self.db_stmt)
# self.fields = [f.name for f in self.query.description]
# pass
def __exit__(self, exc_type, exc_value, traceback):
# is this necessary?
# self.db_con.close()
pass
def result(self):
for entry in self.query.fetchall():
yield dict(zip(self.fields, entry))
# not working
# for entry in self.query:
# yield dict(zip(self.fields, entry))
# not working
# yield dict(zip(self.fields, entry))
# pass
then i try it on ./manage.py shellby typing
from django.db import (connection as con)
from mine.db import query_00
# expected usage, attempt 1
q = query_00(con, 'SELECT * FROM master.years a where a.year = %s', [str(2019),])
for b in q.result():
print(b)
# expected usage, attempt 2
with query_00(con, 'SELECT * FROM master.years a where a.year = %s', [str(2019),]) as q:
for b in q.result():
print(b)
python-3,django-2,postgresql-9
(sorry for my english)
so, after reading the documentation, i realize that the connection was closed inside my init method.
class query_00:
def __init__(self, db_con, db_sql, db_stmt = []):
self.db_con = db_con
self.db_sql = db_sql
self.fields = []
with db_con.cursor() as self.query:
self.query.execute(db_sql, db_stmt)
self.fields = [f.name for f in self.query.description]
# the connection only happend inside "with:" block
# the connection, was already closed here (after with:)
so, i just have to keep cursor() on a variable
class query_01:
def __init__(self, db_sql, db_stmt):
self.db_sql = db_sql
self.db_stmt = db_stmt
self.query = connection.cursor()
...
put query.execute() on another method
...
def execute(self):
self.query.execute(self.db_sql, self.db_stmt)
self.fields = [f.name for f in self.query.description]
...
on result()
...
def result(self):
self.execute()
for entry in self.query:
yield self.keyvalue(entry)
...
then my class is working
with query_00('SELECT * FROM master.years a where a.year = %s', [str(2019),]) as q:
for b in q.result():
print(b)

operation parameter must be str in sql/python

import sqlite3, time, datetime, random, random
class DatabaseManager(object):
def __init__(self, db):
self.conn = sqlite3.connect(db)
self.conn.execute('pragma foreign_keys = on')
self.conn.commit()
self.c = self.conn.cursor()
def query(self, arg):
self.c.execute(arg)
self.conn.commit()
return self.c
def fetch(self):
self.c.fetchall()
self.conn.commit()
return self.c
def __del__(self):
self.conn.close()
dbmgr = DatabaseManager("connect.db")
while 1 > 0:
def quantity():
x = 1
file = open("john.txt", "r")
for line in file:
x = random.randint(100,10000000)
func = "INSERT INTO test (playerNAME) VALUES (?, ?)", line, x
dbmgr.query(func)
You can ignore the while 1 > 0, that was part of the code I deleted to specifically ask my question. When I call the function quantity() (in another part of code I also deleted for the questions sake), I get an error that states:
Traceback (most recent call last):
File "C:\Users\senarsky.CAL\Documents\2016Sem2\Sqlite-connect.py", line 210, in
quantity()
File "C:\Users\senarsky.CAL\Documents\2016Sem2\Sqlite-connect.py", line 68, in quantity
dbmgr.query(func)
File "C:\Users\senarsky.CAL\Documents\2016Sem2\Sqlite-connect.py", line 14, in query
self.c.execute(arg)
ValueError: operation parameter must be str
I am not sure how to make the func line a string without using insecure sql formatting...
Enclose your query parameters in a tuple:
query = "INSERT INTO test (playerNAME) VALUES (?, ?)"
parameters = (line, x)
Modify the query method to accept both query and parameters:
def query(self, query, params=None):
self.c.execute(query, params)
self.conn.commit()
return self.c
And then call as:
dbmgr.query(query, parameters)

Timeit module for qgis plugin

I'd like to use the python module timeit to time some functions in my QGIS plugin.
Here, I've called the time it function within a function that I call at the end of the last function. It seems, though, that the plugin is taking even longer to run than usual and I am wondering if i'm calling the timer in the wrong place. Is there a better way to set this up?
class myPluginName:
def firstFunction(self):
...
self.secondFunction()
def secondFunction(self):
...
self.timeThings()
def run(self):
self.firstFunction()
def timeThings(self):
QMessageBox.information(None, 'First Function', 'Time : %s' % timeit.timeit(self.firstFunction,number=1)
QMessageBox.information(None, 'Second Function', 'Time : %s' % timeit.timeit(self.secondFunction,number=1)
UPDATE: After following some advice, i've tried to implement the wrapper in the following way. I get however, a TypeError: firstFunction() takes exactly 1 argument (2 given) on ret = func(**args, **kwargs)
def time_func(func):
try:
name = func.__name__
except:
name = func.f__name
def tf_wrapper(*args, **kwargs):
t = time.time()
ret = func(*args, **kwargs)
QMessageLog.logMessage("{}: {}".format(name, time.time() - t))
return ret
return tf_wrapper
class myPlugin:
def initGui(self):
QObject.connect(self.dlg.ui.comboBox,SIGNAL("currentIndexChanged(int)"), self.firstFunction)
#time_func
def firstFunc(self):
registry = QgsMapLayerRegistry.instance()
firstID = str(self.dlg.ui.firstCombo.itemData(self.dlg.ui.firstCombo.currentIndex()))
secondID = str(self.dlg.ui.secondCombo.itemData(self.dlg.ui.secondCombo.currentIndex()))
self.firstLayer = registry.mapLayer(firstID)
self.secondLayer = registry.mapLayer(secondID)
#time_func
def secondFunc(self):
...
self.thirdFunc()
def thirdFunct(self):
...
def run(self):
self.dlg.ui.firstCombo.clear()
self.dlg.ui.secondCombo.clear()
for layer in self.iface.legendInterface().layers():
if layer.type() == QgsMapLayer.VectorLayer:
self.dlg.ui.firstCombo.addItem(layer.name(), layer.id())
self.dlg.ui.secondCombo.addItem(layer.name(), layer.id())
result = self.dlg.exec_()
if result == 1:
self.secondFunction()
OK, I don't know your exact situation, but I'd set it up though decorators:
import time
def time_func(func):
try:
name = func.__name__
except:
name = func.f_name
def tf_wrapper(*args, **kwargs):
t = time.time()
ret = func(*args, **kwargs)
print("{}: {}".format(name, time.time() - t)) # Or use QMessageBox
return ret
return tf_wrapper
class myPluginName:
#time_func
def firstFunction(self):
pass
#time_func
def secondFunction(self):
pass
def run(self):
self.firstFunction()
myPluginName().firstFunction()
With this code, any function wrapped in time_func will have the time taken to execute the function printed when it returns, along with its name. E.g. running it will print:
firstFunction: 1.430511474609375e-06
For your TypeError, you need to change;
def firstFunction(self):
pass
To:
def firstFunction(self, index):
pass

Python class function not returning variable

I think I may be overlooking something simple. I have a class with a constructor defined. In one of the functions I make a call to an api an store the response in a variable. I'd like to return that variable. kind of like, info = MyClass(), data = info.somefunctuon(). In my case data always returns None.
here is a snippet of what I have.
class SomeAPI(object):
def __init__(self, br, cj, username, password, logged_in='', api_id='', data=''):
self.br = br
self.cj = cj
self.logged_in = False
self.username = username
self.password = password
self.api_id = api_id
br.set_cookiejar(self.cj)
br.set_handle_robots(False)
def _login_check(f):
#wraps(f)
def wrapper(self):
if self.log_in():
f(self)
else:
raise MyError('Not Logged In')
return wrapper
def log_in(self):
auth_data = {'cmd': 'auth', 'params': {'username': self.username,
'password': self.password}}
if not self.logged_in:
self.br.open('https://someurl.com/auth', dumps(auth_data))
data = loads(self.br.response().read())
status = data['response']['status']
if status == 'OK':
api_id = data['response']['api_id']
self.logged_in = True
self.api_id = api_id
else:
raise MyError(status)
return self.logged_in
#_login_check
def campaigns_list(self):
campaigns_list_data = {'cmd': 'ab_campaigns'}
raw = self.br.open('https://someurl.com/{}'.format(self.api_id),
dumps(campaigns_list_data))
json_resp = raw.read()
resp = loads(json_resp)
status = resp['response']['status']
if status == 'OK':
data = resp['response']['Ad Campaigns']
return data
when I do:
info = SomeAPI(mechanize.Browser(), cookielib.LWPCookieJar(), 'MyName', '12345')
data = info.campaigns_list()
print data
I always get None. I know that I get the data because when i replace return with print I get the expected response. I thought maybe I'd need to define data on the constructor, but then each function of my class would need its own variable defined. I think it would get messy.
Any suggestions please let me know. Thank you!
Your decorator _login_check calls the function it wraps, but it doesn't return whatever the function returns.
Change:
def _login_check(f):
#wraps(f)
def wrapper(self):
if self.log_in():
f(self)
else:
raise MyError('Not Logged In')
return wrapper
to:
def _login_check(f):
#wraps(f)
def wrapper(self):
if self.log_in():
return f(self)
else:
raise MyError('Not Logged In')
return wrapper

Why SQLAlchemy Session.filter().update/delete raise read-only exception when using RoutingSession?

The following is my config, slave is read-only:
engines = {
'master': create_engine(
settings.MASTER_URL, echo=settings.ECHO_SQL, pool_recycle=3600),
'slave': create_engine(
settings.SLAVE_URL, echo=settings.ECHO_SQL, pool_recycle=3600),
}
class RoutingSession(Session):
def get_bind(self, mapper=None, clause=None):
#return engines['master']
if self._flushing:
return engines['master']
else:
return engines['slave']
DBSession = scoped_session(sessionmaker(class_=RoutingSession))
When I do :
s = DBSession()
#synchronize_session=False makes execution faster
s.query(Model).filter(Model.id == 1).delete(synchronize_session=False)
s.commit()
it raises an exception that it couldn't delete because of "read-only".
How to rewrite my RoutingSession to make the above 'delete' use 'master' database
---Edit1---
I've done more test. The above 'delete' is different from the following 'delete' which RoutingSession will return 'master':
model = s.query(Model).filter(Model.id == 1).first()
s.delete(model)
s.commit()
A query.delete() is not part of a "flush", so typically if you're using the routing session recipe, you want to implement using_bind() and call upon that before an operation like a delete():
class RoutingSession(Session):
def get_bind(self, mapper=None, clause=None ):
if self._name:
return engines[self._name]
else:
# other cases here
_name = None
def using_bind(self, name):
s = RoutingSession()
vars(s).update(vars(self))
s._name = name
return s
then to use:
Session().using_bind("master").query(Model1).delete()

Categories