This question already has answers here:
Are global variables thread-safe in Flask? How do I share data between requests?
(4 answers)
Closed 3 years ago.
I am trying to add data to my mysql database with a HTTP post request, but in the way it's set up now, if we post more than once, the data from the first post gets changed to 0 because I declare all the variables in the same definition. How can I fix this?
I have tried to declare a global variable in a second def, but it just loops that def instead of the one I have now.
#!/usr/bin/env python
import pymysql.cursors
from flask import Flask, request
from Crypto.Cipher import AES
connection = pymysql.connect('localhost','esp', 'password', 'points')
app = Flask(__name__)
#app.route('/post', methods = ["POST"])
def post():
hits1 = 0
hits2 = 0
punch1 = 0
punch2 = 0
kick1 = 0
kick2 = 0
takedown1 = 0
takedown2 = 0
print(request.data)
cipher = AES.new("abcdefghijklmnop")
decryptedData = cipher.decrypt(request.data)
data = decryptedData.decode("utf-8")
print(data)
print(data)
if(data[:1]=="e"):
if(data[1:2] == "1"):
hits1+=1
print(hits1)
if (data[:1]=="1"):
if(data[1:2]=="1"):
punch1+=1
elif(data[1:2]=="2"):
kick1+=1
elif(data[1:2]=="3"):
takedown1+=1
elif(data[:1]=="2"):
if(data[1:2]=="1"):
punch2+=1
elif(data[1:2]=="2"):
kick2+=1
elif(data[1:2]=="3"):
takedown2+=1
points1 = punch1 + kick1 * 2 + takedown1 * 3
points2 = punch2 + kick2 * 2 + takedown2 * 3
print(points1)
print(points2)
try:
with connection.cursor() as cursor:
cursor.execute("INSERT INTO points values({0}, {1}, {2}, {3}, {4}, {5})".format(1, hits1, kick1, punch1, takedown1, points1))
cursor.execute ("INSERT INTO points values({0}, {1}, {2}, {3}, {4}, {5})".format(2, hits2, kick2, punch2, takedown2, points2))
connection.commit()
print ("Data committed")
return 'ok'
except:
connection.close()
app.run(host='0.0.0.0', port= 8090)
The value of the previous post gets changed to 0, but i want to keep that value
It seems that you want to keep the variables you define at the top of your function (hits1, hits2...). The problem, as you stated, is that these variables are redefined every time your function is called.
The simplest way to do that (though a questionable design) is to use global variables. To define a global variable, you could do this:
hits1 = 0
hits2 = 0
# ...
#app.route('/post', methods = ["POST"])
def post():
global hits1, hits2
# ...
That way, the values will be kept between requests. A way that I (personnally) prefer, though it's still the same idea, is to keep your data in a "Storage" class:
class Storage:
hits1 = 0
hits2 = 0
# ...
#app.route('/post', methods = ["POST"])
def post():
# Instead of just using hits1, hits2, ...
# We now use Storage.hits1, ...
# Example:
# ...
Storage.points1 = Storage.punch1 + Storage.kick1 * 2 + Storage.takedown1 * 3
# ...
That works. But of course, this is forgotten every time you restart your Flask application. If you want actual persistence (which is what you're trying to achieve, as you're using a database), is something that would query the database (potentially with a cache in order to limit the number of queries) every time a user makes a request to your server:
class Database:
def __init__(self):
# Connect to your database
self._hits1 = None
#property
def hits1(self):
if self._hits1 is None:
# self._hits1 = (Load data from the database)
return self._hits1
# ...
database = Database()
#app.route('/post', methods = ["POST"])
def post():
# Loads from the database
hits1 = database.hits1
# ...
# In this case, you'd probably want to move your INSERT query to your database class
A few comments: if you want to keep your values between requests, it's probably that you want to UPDATE your database instead of INSERTing data (but that's just my interpretation of your code).
Also, using an_sql_request.format(data) is a very bad practice, as it can help potential SQL injections. Most database drivers offer a way of preparing queries. For example with mysql.connector:
cur = connection.cursor()
sql = "INSERT INTO MyTable (Col1, Col2) VALUES (%s, %s)"
cur.execute(sql, (value_for_col1, value_for_col2))
Related
I started working with flask-python recently.
I am trying to send an array read from the database to a class that defines a form.
Here is my class :
# livraison Form Class
class livraisonForm(Form):
list_assurances=['-', u'Aucune assurance trouvée']
type_assur = SelectField(u'Type d\'assurance', choices=list_assurances)
# INIT function :
def __init__(self, list_assurances, *args, **kwargs):
super(Form)
self.list_assurances = list_assurances
Here is how I am trying to pass the array to the init function
def add_livraison():
form = livraisonForm(request.form, get_assurances())
the get_assurances() function returns an array as mentionned below :
def get_assurances():
# Create db cursor
cur = mysql.get_db().cursor()
# Get user by username
result = cur.execute("SELECT ID_ASSURANCE, DESCRIPTION FROM type_assurance ")
if result > 0:
# Get assurances list
data = cur.fetchone()
# Close connection
cur.close()
return [(i[0]+'', i[1]+'') for i in data]
# Close connection
cur.close()
return ['-', u'Aucun assur trouvée']
unfortunately, I am having this problem concerning the form class :
TypeError: 'UnboundField' object is not callable
I tried to delete the list_assurances variable from the form and called the function directly but I got a problem saying that the database has no attribute cursor.
I would like to know what is the right way to send an array to a class -form class- in flask.
Thank you so much
form = livraisonForm(request.form, get_assurances())
Here you're actually assigning the request.form to the self.assurances, not get_assurances() as you should.
Try it like that:
form = livraisonForm(get_assurances())
I would like to test if a table is empty using pony orm.
At first I connect to the database and say generate mappings.
I'm using the 'Names' table as an example here and connect to a postgres database
from pony.orm import *
class Names(db.Entity):
name = Required(str)
#db_session
def populate_names(name_list):
for name_element in name_list:
db.insert("Names", name=name_element)
#db_session
def test_empty():
temp = False
# if Names is empty, set temp = True
if Names ... :
temp = True
return temp
if __name__ == "__main__":
characters = ['James', 'Elisabeth', 'Paul', ...]
db = Database()
db.bind(provider='postgres', user='', password='', host='', database='')
# generate_mappings already creates empty tables
db.generate_mapping(create_tables=True)
empty = test_empty()
if empty is True:
populate_names(characters)
I couldn't find anything in the Pony Docs about checking if a table is empty.
if Names is None:
The line above gives me 'False' because the table already exists.
Does anyone know a solution to that?
The simplest way is to write:
with db_session:
if not Names.select().exists():
populate_names()
Alternatively you can put test inside populate_my_entity():
#db_session
def populate_names(name_list):
if Names.select().exists():
return
for name_element in name_list:
db.insert("Names", name=name_element)
The question is simple, the answer I dont know...
I'm newbie with testing and I have problems testing class for drive a sql3 database. What is the best way for test a class like this? Test the class or test the init function is not a problem, but the others? the test insert a test row?
import sqlite3
class DataBase:
def __init__(self):
self._database_path = 'data.sql'
self._conn = sqlite3.connect(self._database_path)
self._cursor = self._conn.cursor()
def get(self, sql):
# select
self._cursor.execute(sql)
dataset = []
for row in self._cursor:
dataset.append(row)
return dataset
def post(self, sql):
# insert
self._cursor.execute(sql)
self._conn.commit()
Thank you for all of you, thank you for all your answers!!
You can use the rollback function of the database.
Just replace self._conn.commit() with self._conn.rollback() and you can test the validity of your sql with no effects on the data.
If you need to test a series of actions (i.e: get data->modify data->insert new data->remove some data->get data again) you can remove all the _conn.commit() in your code, run the tests and finally call _conn.rollback().
Example:
import sqlite3
class DataBase:
def __init__(self):
self._database_path = 'data.sql'
self._conn = sqlite3.connect(self._database_path)
self._cursor = self._conn.cursor()
def get(self, sql):
# select
self._cursor.execute(sql)
dataset = []
for row in self._cursor:
dataset.append(row)
return dataset
def post(self, sql):
# insert
self._cursor.execute(sql)
def delete(self, sql):
# delete
self._cursor.execute(sql)
def rollback(self):
self._conn.rollback()
# You do your tests:
db = DataBase()
data = db.get('select name from table')
new_data = ['new' + name for name in data]
db.post('insert into table values {}'.format(','.join('({})'.format(d) for d in new_data)))
db.delete('delete from table where name = \'newMario\'')
check = bool(db.get('select name from table where name = \'newMario\''))
if check:
print('delete ok')
# You make everything as before the test:
db.rollback()
I think the CursorTests in official sqlite3 tests is a good example.
https://github.com/python/cpython/blob/master/Lib/sqlite3/test/dbapi.py#L187
You can write setUp and tearDown methods to set up and rollback the database.
from unittest import TestCase
class TestDataBase(TestCase):
def setUp(self):
self.db = DataBase()
def test_get(self):
pass # your code here
def test_post(self):
pass # your code here
With using only the cursor instance of a sqlite3.connect I want to know if it (cursor instance) has executed a query or not.
def f(cur):
cur = connection.cursor()
if user decided to:
cur.execute("select * from aTable Where aCondition")
return cur
...
if f(cur).fetchone() == None:
print("No record found")
else:
...print records...
My problem is that with only using the returning cur, I don't know how to distinguish (in the return place) between the situation that user decides not to order the query and just cancel the search with the situation in which the result set is just is empty.
In my current code, in both situations the "No record found" message will be display. Is there any trick (for example through sqlite) to specify any query has just been executed regardless of the result?
Edit:
Please forgive me for not explaining my situation as it is in the first place (I'm too inexperienced at the field)
The deadened I'm already in is a design as below. I don't wanna use another global variable or changing the childWin class to receive another parameter when instantiating. This way the only channel to interact between two windows seems to be the cur object (which lives up after the cw instance diminished). So what should I do?
class mainWin():
self.cw=childWin()
self.cur=self.cw.cur
self.wait_window(self.cw)
if self.cur==None:
**whether search has been canceled (by hitting cancel button) or result is empty?**
else:
use the returned records
class childWin(tkinter.Toplevel):
def __init__(self):
global con
self.cur=con.connection.cursor()
def cancel_button:
self.destroy()
def search_button():
self.cur.execute("select * from aTable Where aCondition")
self.destroy()
This is a case of mismatched abstraction levels.
You're mixing (a) user actions, with (b) fundamental database operations.
User actions should be at a higher level than basic database operations:
def user_interaction():
...
if user decided to:
cur = run_query()
...
def run_query():
cur = connection.cursor()
cur.execute("select * from aTable Where aCondition")
return cur # open resultset..
When writing low level database functions it is usually a good idea to not leave cursors open with pending results since (i) there's a limited number of open cursors that you can have, and (ii) you can block other processes potentially causing a deadlock. Write your database layer so that it returns exactly the data you need, e.g.:
def get_foo_record():
cur = connection.cursor()
cur.execute("select * from aTable Where aCondition limit 1")
return cur.fetchone()
def user_interaction():
...
if user decided to:
record = get_foo_record()
if record is None:
print("No record found")
else:
...do something with record...
i.e. you distinguish not-ran vs empty-result by separating user interaction concerns from low-level code and make low-level (database) code as simple and deterministic as you can.
If you're determined to hack your way to the finish, then perhaps the cur.description attribute will help you:
>>> import sqlite3
>>> sqlite3.connect('foo.db')
<sqlite3.Connection object at 0x0075B410>
>>> cn = _
>>> c = cn.cursor()
>>> print c.description
None
>>> c.execute('create table foo (n int)')
<sqlite3.Cursor object at 0x02B6CC60>
>>> print c.description
None
>>> c.execute('select * from foo')
<sqlite3.Cursor object at 0x02B6CC60>
>>> print c.description
(('n', None, None, None, None, None, None),)
>>>
i.e. cursor.description will be a tuple after a select.
I haven't used this myself for this purpose so "buyer be ware", "here lie dragons", etc., etc.
To capture exceptional events (like the user cancels the search) you can use exceptions:
def do_search(cur):
cur=connection.cursor()
if user cancels:
raise RuntimeError("canceled")
cur.execute("select * from aTable Where aCondition")
return cur
try:
results = do_search(cur)
except RuntimeError:
print "User canceled"
else:
results = list(results)
if not results:
print("No record found")
else:
...print records...
to your edit: don't mix up GUI and logic. The windows should collect user input, but the search should be done somewhere else. Use additional flag for cancelation:
def do_search(condition):
... somehow construct select from condition ...
return records
class mainWin():
def start_search(self):
search_window = SearchWindow()
self.wait_window(search_window)
if search_window.canceled:
... canceled ...
else:
records = do_search(search_window.condition)
... use the returned records ...
class SearchWindow(tkinter.Toplevel):
def __init__(self):
self.canceled = True
def cancel_button(self):
self.canceled = True
self.destroy()
def search_button(self):
self.canceled = False
self.condition = "aCondition"
self.destroy()
This question already has answers here:
Python Unbound Method TypeError
(3 answers)
Closed 9 years ago.
I am having difficulty passing a variable from one function to another function in another python script. I have read the other answers but they have not really helped on this subject.
This is the first file I want to send the variable to( some code omitted for clarity )
# TestGUI.py
from Tkinter import *
import serial
import os
class Testgui:
def __init__(self, master):
def writetoBOT(self,instruct):
ser = serial.Serial(6)
ser.baudrate = 9600
ser.parity = serial.PARITY_NONE #set parity check: no parity
ser.timeout = 1 #non-block read
ser.writeTimeout = 2 #timeout for writ
if(ser.isOpen() == False):
ser.open()
print ser.portstr # check which port was really used
ser.write(instruct)
else :
ser.write(instruct)
This is the sceond file:
# TestGUI_2.py
from TestGUI import Testgui
class Tracker:
def __init__(self):
pass
def drive(self,cords, cords1):
while( cords >= 320):
l='l'
Testgui.writetoBOT(l) # This is the problem line
TypeError: unbound method writetoBOT() must be called with TestGUI instance as first argument (got str instance instead)
writetoBOT takes 2 arguments: self and instruct.
call it with a Testgui instance:
tgui=Testgui(your_master)
tgui.writetoBOT(l)
If you want to call it with Testgui class, you still need to pass an instance of Testgui:
tgui=Testgui(your_master)
Testgui.writetoBOT(tgui, l)
Alternatively, you can make common space for this two scripts, it acn by database - sqllite
For example,
# file1.py
import sqlite3
con = sqlite3.connect('messages.db')
cur = con.cursor()
#cur.execute('CREATE TABLE message (id INTEGER PRIMARY KEY, name TEXT, content TEXT, read INTEGER)')
#con.commit()
for x in range(100000):
if x in range(1, 500):
cur.execute('INSERT INTO message (id, name, content, read) VALUES(NULL, "Guido", "van Rossum", 0)')
con.commit()
# file2.py
import sqlite3
import time
con = sqlite3.connect('messages.db')
cur = con.cursor()
def listen():
messages = cur.execute('SELECT * FROM message WHERE read=0')
if not messages:
return False
for m in messages:
print 'get message ', m
cur.execute("UPDATE message SET read=1 WHERE id=?", m[0])
con.commit()
print 'update db'
return True
while True:
listen()
time.sleep(5)
You declared Testgui as a class. This is to be understood as a skeleton or wireframe (beware, this is a shortcut, not the reality). You need to first create a "real" object out from this skeleton in order to use it.
testgui=Testgui(amaster)
It is possible in classes to have methods (bound functions) that apply at class level. These are called static methods or class methods. They have to be decorated in python.
See http://en.wikipedia.org/wiki/Object_oriented_programming for more information.