Take user input from Python to SQL query - python

I am creating a store front page where the user will be able to search for items inside of an SQL data base. I am having issues with the python logic where I am trying to use the WHERE logic to find what the user hass entered. Here is my code:
username = input("Enter your username >>> ")
password = input("Enter your password >>> ")
try:
cursor.execute('SELECT * FROM users ORDER BY email')
except:
print("The database does not exist")
else:
list_of_users = cursor.fetchall()
def login(email: str, pwd: str, list_of_users: [()]) -> bool:
for db_email, db_pwd in list_of_users:
if (email == db_email) and (pwd == db_pwd):
return True
return False
#----------Storefront----------#
while login(username, password, list_of_users) == True:
search_bar = input("Enter what item you would like to look up >>> ")
sql = "SELECT * FROM item_in_stock WHERE item_name = "
cursor.execute(sql , search_bar)
for row in iter(cursor.fetchone, None):
print(row)
also if someone has a better way of testing to see if what I get out of the table is the correct value that I am looking for instead of using
for row in iter(cursor.fetchone, None):
print(row)
then please do share as I do not understand what that for loop is doing.
When I run the program, this is what I get:
Enter your username >>> joe#gmail.com
Enter your password >>> qwerty
Enter what item you would like to look up >>> Jumper
Traceback (most recent call last):
File "C:/Users/jerem/PycharmProjects/assignment_core/main.py", line 30, in <module>
cursor.execute(sql , search_bar)
sqlite3.OperationalError: incomplete input
No clue how to fix this.

cursor.execute as you are using it accepts two parameters, sql and parameters. I believe, according to sqlite docs and sqlite parameter reference, that you should define your string sql with sql = "SELECT * FROM item_in_stock WHERE item_name = ?" and pass parameters into cursor.execute in a tuple.
All in all, you might want to try something along the lines of:
while login(username, password, list_of_users) == True:
search_bar = input("Enter what item you would like to look up >>> ")
sql = "SELECT * FROM item_in_stock WHERE item_name = ?"
cursor.execute(sql, (search_bar))
for row in iter(cursor.fetchone, None):
print(row)

Related

Issues with IF statements and Pypyodbc

I am brand new to Python and know very little. I have connected my MS-Access file to my python using Pypyodbc. I am attempting to query with it using a user input however, I need it to be able to change based on the input of the user rather than having lots of hard-coded options. Here is the code and any help is greatly appreciated. Thanks.
Side note: I would be adding more options to this if statement in the future (a total of 5 accepted user inputs)
import pypyodbc
conn = pypyodbc.connect(r'Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=C:\DB\FILM_SMITH.accdb;')
cursor = conn.cursor()
input("What would you like to search for? ")
if input == "genre":
genre = input("Please input the required genre: ")
connstring = "select * from Films where Genre = " + genre
if input == "rating":
rating = input("Please input the required age rating: ")
connstring = "select * from Films where BBFC = " + rating
else:
print("Invalid Entry")
for row in cursor.fetchall():
print (row)
First, your code is prone to SQL injection attacks. You should pass the parameter dynamically, instead of putting it inside the string. See this for example.
Now to your actual question. If you want to avoid some code repetition, you can make a list of possible fields. You should have a way to restrict the possible fields, otherwise the user might provide an invalid field. Here is an example:
available_fields = ['genre', 'rating', 'another_field']
fld = input('What field would you like to search for?')
assert fld in available_fields, 'Invalid field'
value = input('Please enter a value you want to search for: ')
query = f'select * from Films where {fld} = ?'
# Now run the query with *value* as a dynamic parameter
Your requirements might vary, so probably there is a better solution for your case. But that should help, I hope.
Here is another way of doing it to prevent code duplication using a dictionary.
the dictionary is structured like this
"key_you_want_to_search":["Question_you_want_the_user_to_answer","Name_of_your_SQL,column"]
import pypyodbc
conn = pypyodbc.connect(r'Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=C:\DB\FILM_SMITH.accdb;')
cursor = conn.cursor()
dictionary = {"genre": ["Please input the required genre: ", "Genre"],
"rating": ["Please input the required age rating: ", "BBFC"]}
user_input = input("What would you like to search for? ")
if user_input in dictionary:
temp = input(dictionary[user_input][0])
connstring = f"select * from Films where {dictionary[user_input][1]} = {temp}"
else:
print("Invalid Entry")
for row in cursor.fetchall():
print(row)

How would I make my code which creates accounts safe from SQL-Injections?

This is my code:
import sqlite3
connection = sqlite3.connect('data.db')
cursor = connection.cursor()
cursor.execute('CREATE TABLE IF NOT EXISTS accounts(name text primary key, password text)')
connection.commit()
connection.close()
continue_loop = True
yes_no_value = input("Would you like to create a new account? (yes/no): ")
if yes_no_value == 'no':
continue_loop = False
while continue_loop:
user = input("Enter username: ")
password = input("Enter password: ")
connection = sqlite3.connect('data.db')
cursor = connection.cursor()
cursor.execute(f'INSERT INTO accounts VALUES("{user}", "{password}")')
connection.commit()
connection.close()
print('success')
yes_no_value = input("Would you like to create a new account? (yes/no): ")
if yes_no_value == 'no':
continue_loop == False
It would help if someone could send me my code but edited to be safe from SQL injections, and explain.
In the code you provided, the code that's at risk from injection is this line:
cursor.execute(f'INSERT INTO accounts VALUES("{user}", "{password}")')
So, what you have to worry about is the safety of the values of user and password at that point. You're allowing the user to enter them from the console, so they could basically enter anything.
You could instead:
cursor.execute(f'INSERT INTO accounts VALUES(?, ?)', (user, password))
This has the same result, but now cursor.execute() (or an underlying call) turns the values of user and password into the values for SQL and has a chance of catching shenanigans in the process.

Query function suddenly returning `None` instead of the item it should be retruning

I did some minor refactoring to some working code. All I did was add 2 functions to clean up how input and it's assignment was handled. I did not change anything about the query_pswd_by_name function but now it doesn't return the password, it returns None. Everything else works perfectly. Any ideas what is going on? Here is the code:
import secrets
import string
import sqlite3
import pyperclip
import optparse
#CREATE PASSWORD OF GIVEN LENGTH
def get_pass(length):
return "".join(secrets.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits + string.punctuation) for x in range(length))
def get_pass_length():
length = int(input("Enter the length of password: "))
password= get_pass(length)
print(password)
pyperclip.copy(password)
print('Password copied to clipboard')
def create_and_store_pwsd():
password = get_pass_length()
name = str(input("Enter name for password: "))
#CREATE DATABASE CONNECTION
conn = sqlite3.connect("managerDB.db")
#CREATE CURSOR OBJECT
c = conn.cursor()
#CREATE TABLE IN DISK FILE BASED DATABASE
c.execute("""CREATE TABLE IF NOT EXISTS password_table (
name TEXT,
pswd TEXT
)""")
#c.execute("DELETE FROM password_table")
c.execute("INSERT INTO password_table (name, pswd) VALUES (?, ?)", (name, password))
#COMMIT CHANGES
conn.commit()
conn.close()
def query_pswd_by_name(name):
conn = sqlite3.connect('managerDB.db')
c = conn.cursor()
query_password = "SELECT pswd FROM password_table WHERE name = ?"
c.execute(query_password,(name,))
result = c.fetchall()
for row in result:
pyperclip.copy(str(row[0]))
print("Password copied to clipboard")
print(str(row[0]))
conn.commit()
conn.close()
def input_name_and_query():
name = input('Name of password you wish to query: ')
query_pswd_by_name(name)
create_and_store_pwsd()
input_name_and_query()```
I mean, at face value, it returns None because you never return anything from the function. You are copying it to the clip board.
A bit more detail would be good. What functions were refactored? What is the output to the console of all your print statements?
As an aside, I'd recommend wrapping the module functionality (last two calls) in an if __name__ == "__main__" block

Validating user details using sqlite3 and python

I created a database called finance.db and it contains a table named 'test'. The table takes 5 parameters including 'user' and 'password'. A user is already inserted into the table.
I would like the user to be able to log in by providing their username and password and matching that against the database table 'test'. If the table contains the correct username and password it allows the user to log in.
Here is how I imagine it would work:
import sqlite3
user_name = input('Enter username: ')
user_password = input('Enter password:')
def login_details(username, password):
connection = sqlite3.connect('finance.db')
cursor = connection.cursor()
cursor.execute('SELECT * FROM test')
check = cursor.fetchall()
for i in check:
if username and password in check:
print('works')
else:
print('not in db')
login_details(username=user_name, password=user_password)
Unfortunatelly it always returns 'not in db', even if correct details are inserted. I'm not sure what I am missing, but I suspect that my if statement is simply incorrect, but it does not result in a syntax or other error.
UPDATE:
I solved the problem by extracting the information that I require from a tuple and then storing its value in a variable. Here is what I changed:
for i in check:
user_name_input = i[1]
user_pass_input = i[2]
if user_name_input != username and user_pass_input != password:
print('not in db')
else:
print('in db')
In this part of code
for i in check:
if username and password in check
I suppose that check is a list of tuples that represents all the query matched rows in the table. So i is a tuple and you should compare your variables with the specific positions of the tuple which correspond to the fields username and password. Perhaps something like that:
for i in check:
if username == i[0] and password == i[1]

How to store results from SQL query and use it?

I am trying to see whether the type is either a the letter "T" or between number 1-6 for the specific data entry found with name and password.
sql = 'SELECT type FROM table name WHERE name = "{}" AND password = "{}"'.format(username, password)
and then in psedocode i need something like:
if type =< 5:
int()
elif type = "T"
string()
I am using python 2.7
Here is a full script that will query the mysql DB, and use your above-mentioned logic to print the values. I've included the python code as well as the sample database code for this test case. Let me know if you have any questions.
Python
import pymysql
connection = pymysql.connect(user='username', passwd='password',
host='localhost',
database='database')
cursor = connection.cursor()
NAME = 'Person_A'
PASSWORD = 'Password_A'
query = ("SELECT * FROM My_TABLE WHERE NAME = '%(1)s' AND PASSWORD = '%(2)s';" % {"1" : NAME, "2" : PASSWORD})
cursor.execute(query)
for item in cursor:
type = item[0]
if type.isdigit():
if int(type) <6:
print('Type is a number less than 6')
else:
print('Type is a number but not less than 6')
else:
if type == 'T':
print('Type is a string == T')
else:
print('Type is a string but not the letter T')
MYSQL
CREATE TABLE MY_TABLE (TYPE VARCHAR(255), NAME VARCHAR(255), PASSWORD VARCHAR(255));
INSERT INTO MY_TABLE VALUES ('T','Person_A','Password_A'),('4','Person_A','Password_A'),('7','Person_B','Password_B'),('t','Person_C','Password_C');

Categories