SQLite database query (Python, Bottle) - python

I'm trying to make a function where that returns the name of the logged in user if one can be identified or None if not. i want to do this by finding the session id from the cookie in the Bottle request if present, and using it to look up the user in the sessions table.
My code so far:
def session_user(db):
"""try to
retrieve the user from the sessions table
return usernick or None if no valid session is present
"""
cursor = db.cursor()
sessionid = bottle.request.get_cookie(COOKIE_NAME)
usernick = None
if sessionid:
cursor.execute("SELECT usernick FROM sessions WHERE sessionid=?", (sessionid,))
usernick = cursor.fetchall()
return usernick
The table in database:
DROP TABLE IF EXISTS sessions;
CREATE TABLE sessions (
sessionid text unique primary key,
usernick text,
FOREIGN KEY(usernick) REFERENCES users(nick)
);
When i use the current code in my function i get a unit test error:
line 125, in test_session_user
self.assertEqual(nick_from_cookie, None, "Expected None in case with invalid session id, got %s" % str(nick_from_cookie))
AssertionError: [] != None : Expected None in case with invalid session id, got []

See the cursor.fetchall documentation:
Fetches all (remaining) rows of a query result, returning a list. Note that the cursor’s arraysize attribute can affect the performance of this operation. An empty list is returned when no rows are available.
Since an empty list in Python is a false-y expression this normally works out well - when not doing explicit compares with False/None. Always returning a list also makes code that iterates the result set (or checks the length) easier because no special case for None has to be done.
Use the aptly named fetchone to get a single result record, or None.

Related

Unexpected behaviour in sqlalchemy query

INTRO -
In the below python snippet,
I'm querying and fetching users' results from MySQL with the all(), then iterating the result and adding an address to a list of addresses related to a user, nothing special.
PROBLEM -
until now, I have always did it like this -
address = Address(...)
users = db.query(User).all()
for user in users :
user.addresses.append(address)
db.add(user)
db.commit()
so why when using the "SQL Expression Language" I need to iterate the result this way?
(when omitting the model notation it throws "Could not locate column in row for column")
stmt = select(User).join(Country, User.country_id == Country.id).where(Country.iso_code == iso_code).outerjoin(User.addresses)
related_users: Optional[List[User]] = db.execute(stmt).all()
if related_users:
address_in_db = self.get_or_create_address(...)
for user in related_users:
user.User.addresses.append(address_in_db ) # why this is not user.addresses.append(address)
db.add(user.User) # same here, why not just user
db.commit()

Way to add single quote character in string in constructing oracle query in python

I have this method that creates the query and passes two string parameters. But when I test this it has escape characters '' before the single quote '''.
The query can only accept native queries in string form
I also tried string.replace method but doesnt work
replace('\\', '')
Here is the code
def update_query(self, status, row_id):
return '''UPDATE TABLE SET STATUS = {0} WHERE ID = {1}'''.format(status, row_id)
Here is the sample output:
'UPDATE TABLE SET STATUS = 'Success' WHERE ID = 1'
Thank you
You can also use f-string for formatting your string
def update_query(self,status, row_id):
return f"UPDATE TABLE SET STATUS = '{status}' WHERE ID = {row_id}"
>>> update_query("Success",1)
"UPDATE TABLE SET STATUS = 'Success' WHERE ID = 1"
I think you absolutely should be using prepared statements here, which the other answers don't seem to be recommending (for whatever reason). Try using something along these lines:
sql = "UPDATE TABLE SET STATUS = :status WHERE ID = :id"
cursor.prepare(sql)
cursor.execute(None, {'status':status, 'id':row_id})
One advantage of using prepared statements here is that it frees the user from having to worry about how to properly escape the literal placeholders in the query. Instead, we only need to bind a variable with the correct type to the statement, and Oracle will handle the rest.
you need to add \ in the code
def update_query(self, status, row_id):
return '''UPDATE TABLE SET STATUS = \'{0}\' WHERE ID = {1}'''.format(status, row_id)

how to choose what key to Update?

I want to choose a field to Update from my sqlite3 db using postman by utilizing request.data. However, I receive this error "OperationalError at /
near "?": syntax error". I tried this code
def put(self,request,*args,**kwargs):
connection = sqlite3.connect('/Users/lambda_school_loaner_182/Documents/job-search-be/jobsearchbe/db.sqlite3')
cursor = connection.cursor()
req = request.data
for key in req:
if key == id:
pass
else:
print(key)
cursor.execute("UPDATE users SET ? = ? WHERE id = ?;",(key,req[key],req['id']) )
connection.commit()
cursor.execute("SELECT * FROM users WHERE id=?", (request.data['id'],))
results = cursor.fetchall()
data = []
# if request.data['id']
for row in results:
object1 = {}
col_name_list = [tuple[0] for tuple in cursor.description]
for x in range(0,len(col_name_list) ):
object1[col_name_list[x]] = row[x]
data.append(object1)
cursor.close()
# serializer =PostSerializer(data = request.data )
# if serializer.is_valid():
# serializer.save()
return Response(data)
You won't be able to use ? for identifiers (the database structures, like table and column names). You will need to use string interpolation to put in the column name.
f"UPDATE users SET {key} = ? WHERE id = ?"
? are basically for values (user-supplied data).
https://docs.python.org/3/library/sqlite3.html
Usually your SQL operations will need to use values from Python variables. You shouldn’t assemble your query using Python’s string operations because doing so is insecure; it makes your program vulnerable to an SQL injection attack (see https://xkcd.com/327/ for humorous example of what can go wrong).
Instead, use the DB-API’s parameter substitution. Put ? as a placeholder wherever you want to use a value, and then provide a tuple of values as the second argument to the cursor’s execute() method. (Other database modules may use a different placeholder, such as %s or :1.)

Why can't I compare these form variables using python in my mysql query?

I am trying to check for a string that is being passed from a form in an html page. So the form picks up the user name and then checks the database if it already has been made. If it hasn't, it goes ahead and creates it. My errors are in the part of the logic that looks up that user name.
Note, I have commented out some areas where various errors have popped up:
import mysql.connector
import web
from mysql.connector import Error
import cgi, cgitb
cgitb.enable()
conn = mysql.connector.connect(host='localhost', database='database', user='root', password='root')
cursor = conn.cursor()
form = cgi.FieldStorage()
username = form.getvalue('username')
password = form.getvalue('password')
# check_existence = """
# SELECT username FROM members WHERE username = '%s'
# """
check_existence = """
SELECT username FROM members WHERE username = %s
"""
# cursor.execute(check_existence, username)
# "Wrong number of arguments during string formatting")
cursor.execute(check_existence, (username))
# ^pushes down to con.commit
# cursor.execute(check_existence, (username,))
# ^wrpmg number of arguments during string formatting
# with comma, the error is in commit, with comma, its in execute
conn.commit()
matches = cursor.rowcount()
Now the error is pointing to conn.commit. Though this is depending on the syntax, sometimes it points to the line above it.
Error:
=> 203 conn.commit()
<class 'mysql.connector.errors.InternalError'>: Unread result found.
args = (-1, 'Unread result found.', None)
errno = -1
message = ''
msg = 'Unread result found.'
In my limited experience, commit() is only used to save (commit) updates to the database. It looks like you're executing a select query, but doing nothing with the results, and the error is related to that. Try moving the commit to the end, or doing away with it. Try using/doing something with the results stored in the cursor. I believe the latter is the solution.
The .commit method was off to a start but it wasn't the only problem with the code. I had two problems though one of them is not posted in the original post, I will explain both.
A) cursor.rowcount returns -1. Not sure why but it does. My understanding of it was that it will return the number of rows. But you can use cursor.fetchall() instead. This will return matches in an array....but if the array is empty, it'll return an empty array.
So I used this logic:
if not(cursor.fetchall()):
the set/array is empty>> Create user
else:
something was found >>dont create user
B) This was in the rest of my code. I was checking if the connection was connected:
if conn.is_connected():
The problem with doing this is that if you do this after a .execute, it will return false. So I put it higher up in the logic, to check right when it attempts to connect to the database.

Python how to know if a record inserted successfully or not

I'm using Python MySQL Connector, I inserted a record into database, and it was successful. But in Python code, how can I know if it is inserted or not?
My Table does not have a primary key.
def insert(params) :
db_connection = Model.get_db_connection()
cursor = db_connection.cursor()
try :
cursor.execute("""INSERT INTO `User`(`UID`, `IP`) VALUES(%s,%s);""", (params))
db_connection.commit()
except :
db_connection.rollback()
Model.close_db(db_connection)
return result
You can use .rowcount attribute:
cursor.execute("""INSERT INTO `User`(`UID`, `IP`) VALUES(%s,%s);""", params)
print("affected rows = {}".format(cursor.rowcount))
.rowcount This read-only attribute specifies the number of rows that
the last .execute*() produced (for DQL statements like SELECT) or
affected (for DML statements like UPDATE or INSERT). [9]

Categories

Resources