check the presence of a user in a database (python / sqlite3) - python

def dashboard():
p = request.form['Pseudo']
if cur.execute("SELECT * FROM pseudo WHERE user = ?", (p,)) == 0:
cur.execute("INSERT INTO pseudo (user, score, win, coup) VALUES (?,?,?,?)", (p,0,0,0))
conn.commit()
else:
pass
return render_template("index.html",data=liste, Pseudo = p)
Hello, my program doesn't display any error, it's a project for classes and I've been stuck for several hours.
However I try to see if the user is already registered in the database and if so, register him.
However the program acts as if the user is still present in the database.

There are a couple of issues with your design. First, you need to fetch from the executed SQL. Second, you are not checking existence correctly. Third you do not need an else:pass that is assumed.
def dashboard():
p = request.form['Pseudo']
user_check = cur.execute("SELECT * FROM pseudo WHERE user = ?", (p,)).fetchone()
if user_check:
cur.execute("INSERT INTO pseudo (user, score, win, coup) VALUES (?,?,?,?)", (p,0,0,0))
conn.commit()
return render_template("index.html",data=liste, Pseudo = p)

Related

TypeError sqlite python

I am new to sqlite in python and I am trying to do the following:
Extract a certain value from a row in a table and compare it to 100 (it's an INT type normally).
school is a table where I have the following attributes: id, class, nbstudent, nbteachers, nbrepresentative
I use the following function:
def select_school_value(conn, class,m):
"""
Query school by class
"""
cur = conn.cursor()
cur.execute("SELECT * FROM school WHERE class=?", (class,))
record = cur.fetchone()
return record[m]
The function's parameter m is just a number that depends on which attribute I want to extract for the comparaison: nbstudent is m=2, nbteacher is m=3..
When I use my function select_school_value() and compare the returned value with 100, I have a TypeError, the return is a NoneType.
How can I have a integer type return (the type of the attribute I need)?
Thank you in advance.
I guess the issue is in class parameter that you pass to your function and query. Rename it somehow, because Python treats it like a pointer to some class within python code.
Also you have that class=? part which means actuallly "find a class which equals '?'". It should be rewritten too.
I suggest trying this:
def select_school_value(conn,cl,m):
"""
Query school by class
"""
cur = conn.cursor()
cur.execute("SELECT * FROM school WHERE class={}".format(cl))
record = cur.fetchone()
return record[m]

Connection and Cursor inside a class in psycopg2

I would like to use the connection and cursor classes inside a custom made class. I would also like to inherit all the methods associated with the connection and cursor classes. I have done some research on it and found docs and this question related to my problem. I have some code that is working partly. i.e I can insert and update the database. However, I cannot select from the database because doing so returns none even when the row is in the database. Here is my code
from datetime import datetime, timedelta
import psycopg2
import psycopg2.extensions
class DataBase():
"""A class used to create tables in the database. Inherits from
psycopg2.extensions.connection in order to gain access to the cursor,
commit, close, and many other features from the pyscopg module.
"""
def __init__(self):
self.my_connection = psycopg2.connect(database="public", user="public",
password="general", host="127.0.0.1",
port="5432")
self.my_cursor = self.my_connection.cursor()
def query_database(self, sql_statement, *args):
return self.my_cursor.execute(sql_statement, *args)
def commit_query(self):
return self.my_connection.commit()
def fetch_one(self, sql_statement, *args):
result = self.query_database(sql_statement, *args)
if result is None:
return False
return result.fetchone()
def fetch_all(self, sql_statement, *args):
result = self.query_database(sql_statement, *args)
if result is None:
return False
return result.fetchall()
def __del__(self):
self.my_cursor.close()
self.my_connection.close()
############################################################################
class CreateTables(DataBase):
def create_user_table(self):
"""Helper function used to create the user_table"""
sql_statement = '''CREATE TABLE IF NOT EXISTS USERS
(ID SERIAL PRIMARY KEY,
FIRSTNAME TEXT NOT NULL,
LASTNAME TEXT NOT NULL,
USERNAME TEXT NOT NULL UNIQUE,
EMAIL TEXT NOT NULL UNIQUE,
PASSWORD TEXT NOT NULL,
DATETIMEREGISTERED TIMESTAMP NOT NULL);'''
user_table = DataBase.query_database(self, sql_statement)
DataBase.commit_query(self)
return user_table
def create_entries_table(self):
"""Helper function used to create an entries table."""
sql_statement = '''CREATE TABLE IF NOT EXISTS ENTRIES
(ID SERIAL PRIMARY KEY,
TITLE TEXT NOT NULL,
DRINK TEXT NOT NULL,
DATEOFORDER TIMESTAMP NOT NULL,
TIMETODELIVERY TIMESTAMP NOT NULL,
SETREMINDER TIMESTAMP NOT NULL,
USERID INT REFERENCES USERS ON DELETE CASCADE);'''
entries_table = DataBase.query_database(self, sql_statement)
DataBase.commit_query(self)
print("entries table created.")
return entries_table
# test = CreateTables() This is working well
# print(test.create_entries_table())
#####################################################################
class OperateDatabase(CreateTables):
def create_user(self, email, username, *args):
"""Helper function used to create a user"""
sql_statement = """SELECT ID FROM USERS WHERE EMAIL = %s OR
USERNAME = %s;"""
user_in_database = CreateTables.fetch_one(self, sql_statement,
(email, username,))
print("the user in database is :>>", user_in_database)
sql_statement2 = """INSERT INTO USERS (FIRSTNAME, LASTNAME, USERNAME,
EMAIL, PASSWORD, DATETIMEREGISTERED)
VALUES (%s, %s, %s, %s, %s, %s);"""
if not user_in_database:
CreateTables.query_database(self,sql_statement2, *args)
CreateTables.commit_query(self)
return True
return False
data = ("Jkdai", "Jkdal", "Jkdai", "jkdai#gmail.com", "password", datetime.now())
test = OperateDatabase()
print(test.create_user("jkdai#gmail.com", "jkdai", data))
#Inserts the user the very first time implying the insert statement is working
#raises an integrity error the second time implying the select statement is not working.
#Also the print statement defaults to false when it is supposed to return the user's id.
cursor.execute() returns a vendor-defined value (it's not specified in the db-api spec), and for pyscopg2 it is actually documented as returning None indeed, so this:
def query_database(self, sql_statement, *args):
return self.my_cursor.execute(sql_statement, *args)
def fetch_one(self, sql_statement, *args):
result = self.query_database(sql_statement, *args)
if result is None:
return False
return result.fetchone()
will obviously not work as you expect. You could return self.my_cursor() from query_database() instead, ie:
def query_database(self, sql_statement, *args):
self.my_cursor.execute(sql_statement, *args)
return self.my_cursor
def fetch_one(self, sql_statement, *args):
cursor = self.query_database(sql_statement, *args)
return cursor.fetchone()
but there's a fundamental flaw with this code, which is that it's not reentrant (nor thread safe FWIW). Actually, your class should NOT store a cursor as part of it's state and reuse it over and over (db-api cursors are not meant to be used that way) but create a new cursor for every operation (which is the indented use).
Also, you should not rely on __del__(self) to close your connection. The __del__() method is not a proper C++/Java style finalizer and is not even garanteed to be called when the object is collected. Actually, trying to wrap a db connection and cursor in a class is usually not a good idea, at least not this way.

Make a function of SQL query with optional 'where' clauses

Lets say I have a function that query some table company.workers, for example (pseudo code):
def sql_query(dept, prof, hireDate):
q = """SELECT *
FROM company.workers
WHERE department = {0}
AND profession = {1}
AND hire_date > {2}""".format(dept, prof, hireDate)
cur.execute(q)
return cur
What if I want to allow the user the query only on dept and prof, with hireDate being optional? This is the solution I came up with:
def sql_query(dept, prof, *args):
if args:
q = """SELECT *
FROM company.workers
WHERE department = {0}
AND profession = {1}
AND hire_date > {2}""".format(dept, prof, args[0])
else:
q = """SELECT *
FROM company.workers
WHERE department = {0}
AND profession = {1} """.format(dept, prof)
cur.execute(q)
return cur
#the function could be called as so:
sql_query('20', 'Engineer', (2017-12-10))
However I think this is subotimal. What if I want to allow several optional coloumns to query? If I make it two, I have 4 options to handle, which is a lot of else-if blocks to make. Is there a more efficient/elegant solution?
You don't say what SQL DBMS you're using, but here's a block of SQL Server-style code that accepts three variables:
#dept
#prof
#hireDate
The WHERE clause always uses #dept and #prof, and only uses #hireDate if it is not null.
SELECT
*
FROM
company.workers
WHERE
department = #dept
AND
profession = #prof
AND
(
(
#hireDate IS NOT NULL AND hire_date = #hireDate
)
OR #hireDate IS NULL
)
You could then add as many other option variables as needed using this same style, instead of writing separate SQL statements for each combination.
Similar question here. You're right, you don't really want to be manually generating the statement. You could improve your current code by making it more dynamic using a dictionary:
def sql_query(**params):
q = "SELECT * FROM company.workers"
count=0
for i in non_require_param:
if count==0:
q += " WHERE {0} = {1} ".format(i, params[i])
else:
q += " AND {0} = {1} ".format(i, params[i])
count += 1
cur.execute(q)
return cur
Also, sqlite's execute cursor is something to look into. It is cleaner than formatting the statement yourself and handles the datatype conversion:
who = "Yeltsin"
age = 72
cur.execute("""select * from company.workers
where name_last=:name_last and age=:age""",
{"name_last": who, "age": age})

PyQT: Using attributes from SQLite query

I am confused as to how I can use certain attributes that are returned after a query to a local SQLite database. I can populate a qlistwidget with one of the attributes but I do not know how to get the other attributes when a user clicks on the listwidget item.
The following code was created using Eric which pre populates some of the signals and slots
#pyqtSignature("QString")
def on_searchText_textEdited(self, p0):
"""
Slot documentation goes here.
"""
# TODO: not implemented yet
self.resultsList.clear()
self.searchItem = self.searchText.text()
self.search()
#pyqtSignature("QListWidgetItem*")
def on_resultsList_itemClicked(self, item):
"""
Slot documentation goes here.
"""
# TODO: not implemented yet
result = str(item.text())
QMessageBox.about(self, "Clicked Item", "%s")%(result)
#pyqtSignature("")
def on_cancelButton_clicked(self):
"""
Slot documentation goes here.
"""
self.close()
def search(self):
conn = sqlite3.connect("C:\\file.sqlite")
cur = conn.cursor()
sqlqry = "SELECT name, number, size FROM lookup WHERE name LIKE '%s' LIMIT 100;"%("%"+self.searchItem+"%")
try:
c = cur.execute(sqlqry)
data = c.fetchall()
for i in data:
self.resultsList.addItem(i[0])
except sqlite3.Error, e:
QMessageBox.about(self, "Error message", "Error")
So my resultsList gets populated when the user enters text into the line edit but then when a user clicks on an item I get an error with the messagebox saying something about a NoneType and str.
However, what I really need to use are the second and third attributes for somewhere else in my code.
So how do I select that attributes through the itemClicked signal and create two new variables?
i hope that makes sense, it has been a long day going round in circles
You just need to query from the database again and work with the new row.
#pyqtSignature("QListWidgetItem*")
def on_resultsList_itemClicked(self, item):
"""
Slot documentation goes here.
"""
result = str(item.text())
QMessageBox.about(self, "Clicked Item", "%s")%(result)
conn = sqlite3.connect("C:\\file.sqlite")
cur = conn.cursor()
sqlqry = "SELECT name, number, size FROM lookup WHERE name = '%s' LIMIT 1;"%(result)
try:
c = cur.execute(sqlqry)
data = c.fetchone()
# Do something with data
except sqlite3.Error, e:
QMessageBox.about(self, "Error fetching %s"%name, "Error")
Obviously, this doesn't deal with the database santisation issues you might have, and assumes that name is unique in the database.

Can Django models use MySQL functions?

Is there a way to force Django models to pass a field to a MySQL function every time the model data is read or loaded? To clarify what I mean in SQL, I want the Django model to produce something like the following:
On model load: SELECT AES_DECRYPT(fieldname, password) FROM tablename
On model save: INSERT INTO tablename VALUES (AES_ENCRYPT(userinput, password))
Instead of on model load, you can create a property on your model, and when the property is accessed, it can read the database:
def _get_foobar(self):
if not hasattr(self, '_foobar'):
cursor = connection.cursor()
self._foobar = cursor.execute('SELECT AES_DECRYPT(fieldname, password) FROM tablename')[0]
return self._foobar
foobar = property(_get_foobar)
Now after loading, you can refer to mything.foobar, and the first access will retrieve the decryption from the database, holding onto it for later accesses.
This also has the advantage that if some of your code has no use for the decryption, it won't happen.
I would define a custom modelfield for the column you want encrypted/decrypted. Override the to_python method to run the decryption when the model is loaded, and get_db_prep_value to run the encryption on saving.
Remember to set the field's metaclass to models.SubfieldBase otherwise these methods won't be called.
Here is a working solution, based in part on (http://www.djangosnippets.org/snippets/824/):
class Employee(models.Model):
social_security_number = models.CharField(max_length=32)
def _get_ssn(self):
cursor = connection.cursor()
cursor.execute("SELECT AES_DECRYPT(UNHEX(social_security_number), %s) as ssn FROM tablename WHERE id=%s", [settings.SECRET_KEY, self.id])
return cursor.fetchone()[0]
def _set_ssn(self, ssn_value):
cursor = connection.cursor()
cursor.execute("SELECT HEX(AES_ENCRYPT(%s, %s)) as ssn", [ssn_value, settings.SECRET_KEY])
self.social_security_number = cursor.fetchone()[0]
ssn = property(_get_ssn, _set_ssn)
And the results:
>>> from foo.bar.models import Employee
>>> p=Employee.objects.create(ssn='123-45-6789')
>>> p.ssn
'123-45-6789'
mysql> select * from foo_employee;
+----+----------------------------------+
| id | social_security_number |
+----+----------------------------------+
| 31 | 41DF2D946C9186BEF77DD3307B85CC8C |
+----+----------------------------------+
1 row in set (0.00 sec)
It's definitely hackish, but it seems Django won't let you do it any other way at the moment. It's also worth noting that to_python will be called every time you change the value in python in addition to when it is first loaded.
from django.db import connection, models
import re
class EncryptedField(models.TextField):
__metaclass__ = models.SubfieldBase
def to_python(self, value):
if not re.match('^*some pattern here*$', value):
cursor = connection.cursor()
cursor.execute('SELECT AES_DECRYPT(%s, %s)', [value, settings.SECRET_KEY])
return cursor.fetchone()[0]
return value
def get_db_prep_value(self, value):
cursor = connection.cursor()
cursor.execute('SELECT AES_ENCRYPT(%s, %s)', [value, settings.SECRET_KEY])
return cursor.fetchone()[0]
class Encrypt(models.Model):
encrypted = EncryptedField(max_length = 32)
After deep search in the implementation of Django ORM,
I found that it can be solved by something like this:
class EncryptedField(models.BinaryField):
#staticmethod
def _pad(value):
return value + (AES.block_size - len(value) % AES.block_size) * b('\x00')
def _encrypt(self, data):
if not data:
return None
return self.cipher.encrypt(self._pad(data.encode('utf8')))
def _decrypt(self, data):
if not data:
return None
return self.cipher.decrypt(force_bytes(data)).rstrip(b'\x00').decode('utf8')
#property
def cipher(self):
return AES.new(KEY, mode=AES.MODE_CBC, IV=self._iv)
def get_db_prep_value(self, value, connection, prepared=False):
if value is not None:
value = self._encrypt(value)
if value:
value = binascii.hexlify(value)
return value
def get_placeholder(self, value, compiler, connection):
return 'unhex(%s)'
Using Django signals you can do stuff when a model instance is saved, but as far as I know you can't trigger anything on read.
EDIT: My bad, it seems you can do stuff when initializing a model instance.

Categories