Before any theory, Nitish builds a tiny register / login program in Python backed by a MySQL database. The aim is to show you what a database is for: every real application (Google, Facebook, any app you use) stores its data in one and talks to it from code.
Don't treat databases as a boring subject. Once you work at a company you realise they are an interesting topic, and they are what lets you build real-world software.
Setup: what you need
1 · XAMPP
Free software that runs a database server (MySQL / MariaDB) and Apache on your own machine, so you don't need a cloud database. Start Apache and MySQL from the XAMPP control panel.
2 · phpMyAdmin
Comes with XAMPP. A web GUI for your local database at localhost/phpmyadmin: create databases and tables, insert, browse, edit, delete rows.
3 · An editor
Nitish uses PyCharm; any Python IDE works.
4 · A connector library
mysql-connector-python lets Python code connect to MySQL and run SQL.
pip install mysql-connector-python
The project has two files:
main.py: the application (menus, user input, what to show).dbhelper.py: everything that talks to the database.
Databases hold tables, tables hold rows
An important idea: you never store data directly "in a database". Inside a database you create tables, and data lives in a table's rows and columns.
In phpMyAdmin he creates a new database and, inside it, a users table for registration with four columns:
| Column | Type | Why |
|---|---|---|
user_id | INT, A_I (auto-increment), primary key | A unique number per user, like a roll number in college: names can repeat, roll numbers can't. |
name | VARCHAR(255) | Text, up to 255 characters. |
email | VARCHAR(255) | Used to log in. |
password | VARCHAR(255) | Used to log in. |
With A_I ticked you never supply the id yourself. You tell the database: "check what the last user's id was, add one, and fill it in for me." Primary keys are covered in detail in Chapter 4.
The equivalent SQL (you will learn to write this yourself in Chapter 7):
CREATE TABLE users (
user_id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255),
email VARCHAR(255),
password VARCHAR(255)
);
CRUD: the only four things you ever do with data
Whatever project you build with a database, every interaction is one of four operations:
e.g. you send a WhatsApp message, register a new account.
INSERTe.g. logging in: the app checks your email and password against stored rows.
SELECTe.g. editing a comment you posted on a friend's photo.
UPDATEe.g. deleting a message you sent.
DELETEYou use 50 apps a day; imagine any action in any of them and it is always one of these four. Thinking "divide and rule" this way makes working with databases much easier.
In phpMyAdmin you can do all four by hand: Insert a row (leaving user_id blank, since auto-increment fills it), Browse/Search (read), Edit (update) and Delete. But real applications don't open phpMyAdmin; they do the same four operations through code, in Python or any other language. That's what we build next.
Connecting Python to MySQL (dbhelper.py)
Create a DBHelper class. Its constructor connects to the database once; afterwards every method uses that connection.
import mysql.connector
import sys
class DBHelper:
def __init__(self):
# connect to the database once, when the object is created
try:
self.conn = mysql.connector.connect(
host="localhost",
user="root",
password="", # XAMPP's default root password is empty
database="my_app_db"
)
self.mycursor = self.conn.cursor()
except:
print("Some error occurred. Could not connect to database")
sys.exit(0)
else:
print("Connected to database")
- Connection object (
self.conn): your live link to the database. - Cursor (
self.mycursor): the object you use to execute SQL and fetch results. try / except: many things can go wrong (wrong host, wrong password, a database name that doesn't exist, MySQL not running). Nitish demonstrates several of these failures live; on any of them, print a message and exit withsys.exit(0)instead of crashing later.
You can also create the database itself from code (Python or plain SQL) instead of clicking in phpMyAdmin. That's covered in the DDL chapter.
Create: registration
In main.py, a menu-driven program asks the user what to do. Nitish builds the menu with plain input() (a GUI would need more setup):
import sys
from dbhelper import DBHelper
class Flipkart:
def __init__(self):
self.db = DBHelper() # connect once
self.menu()
def menu(self):
user_input = input("""
1. Enter 1 to register
2. Enter 2 to login
3. Anything else to leave
""")
if user_input == "1":
self.register()
elif user_input == "2":
self.login()
else:
sys.exit(1000)
def register(self):
name = input("Enter the name: ")
email = input("Enter the email: ")
password = input("Enter the password: ")
response = self.db.register(name, email, password)
if response:
print("Registration successful")
else:
print("Registration failed")
self.menu()
obj = Flipkart()
The database work lives in DBHelper.register. It builds an INSERT query, executes it, and commits:
def register(self, name, email, password):
try:
self.mycursor.execute("""
INSERT INTO users (user_id, name, email, password)
VALUES (NULL, '{}', '{}', '{}')
""".format(name, email, password))
self.conn.commit() # make the change permanent
except:
return -1
else:
return 1
NULLforuser_id: auto-increment fills it in.conn.commit(): without it, the insert isn't saved. (Commit belongs to TCL, see Chapter 5.)- Return
1/-1so the caller can print success or failure.
Database code goes in one place, application logic in another, and the part the user sees (the GUI) in a third. This is the idea behind MVC (Model–View–Controller), which you'll meet in software development. Here the "view" is just input()/print(), so there are two files instead of three.
Read: login
Login is a read: find a row whose email and password match. fetchall() returns a list of matching rows (each a tuple).
def search(self, email, password):
self.mycursor.execute("""
SELECT * FROM users WHERE email LIKE '{}' AND password LIKE '{}'
""".format(email, password))
data = self.mycursor.fetchall()
return data
def login(self):
email = input("Enter the email: ")
password = input("Enter the password: ")
data = self.db.search(email, password)
if len(data) == 0:
print("Incorrect email/password")
self.login()
else:
print("Hello", data[0][1]) # row 0, column 1 = name
# next: a logged-in menu (view / edit profile, delete account…)
How do we decide whether the login worked? Simply by whether the query returned any rows. An empty list means no user has that email + password.
Try it: the same app, running in your browser
This demo runs a real SQL engine in the page (SQLite compiled to WebAssembly, close enough to MySQL for these queries). Register a few users, log in, and watch the exact SQL each button generates.
The course keeps things simple on purpose. In real code, two things change:
- Never build SQL with
.format()from user input. Someone can type' OR '1'='1as a password and log in as anyone (SQL injection). Use parameterised queries, where the driver escapes values for you:
cursor.execute("SELECT * FROM users WHERE email = %s AND password = %s", (email, password)) - Never store plain-text passwords. Store a salted hash (for example with
bcrypt) and compare hashes.
Use = rather than LIKE for exact matches too; LIKE treats % and _ as wildcards.
Update and delete: the logged-in menu
After a successful login, the app shows a second menu (for example: view profile, edit profile, delete account, log out). Each option is one more CRUD method on DBHelper:
-- Update: edit profile
UPDATE users SET name = 'Nitish Singh' WHERE user_id = 1;
-- Delete: delete account
DELETE FROM users WHERE user_id = 1;
In Python, the same pattern applies: execute(...) then conn.commit(). The full syntax of INSERT, SELECT, UPDATE and DELETE is the subject of the DML chapter.
When data is related to other data (a user's orders, comments, payments), deleting it can break those relationships. That's why many real systems avoid hard deletes. This connects to referential integrity in Chapter 3.
Recap
mysql.connector.connect(host, user, password, database).execute() and returns rows with fetchall().NULL (or skip the column).Conceptual questions
These check whether you understand why, not just what. Several go one step beyond the video.
Why does DBHelper connect once in its constructor instead of connecting inside every method?
Connecting involves network round trips and authentication. Create it once and reuse it (real apps use a connection pool).
What is the cursor's role, as opposed to the connection's?
Connection = the pipe; cursor = what you send SQL through and read rows back from.
Why is keeping database code in dbhelper.py, separate from menu/UI code, a good idea?
Separation of concerns: the idea behind MVC.
A user enters the password ' OR '1'='1 and gets logged in as someone else. Which part of the course's code made this possible?
String-formatting user input into SQL allows SQL injection. Parameterised queries prevent it.