Unit 2.4a Hacks
My Hacks for Unit 2.4a
Database and SQLAlchemy
In this blog we will explore using programs with data, focused on Databases. We will use SQLite Database to learn more about using Programs with Data. Use Debugging through these examples to examine Objects created in Code.
-
College Board talks about ideas like
- Program Usage. "iterative and interactive way when processing information"
- Managing Data. "classifying data are part of the process in using programs", "data files in a Table"
- Insight "insight and knowledge can be obtained from ... digitally represented information"
- Filter systems. 'tools for finding information and recognizing patterns"
- Application. "the preserve has two databases", "an employee wants to count the number of book"
-
PBL, Databases, Iterative/OOP
- Iterative. Refers to a sequence of instructions or code being repeated until a specific end result is achieved
- OOP. A computer programming model that organizes software design around data, or objects, rather than functions and logic
- SQL. Structured Query Language, abbreviated as SQL, is a language used in programming, managing, and structuring data
Questions and Answers
Imports and Flask Objects
Defines and key object creations
- Comment on where you have observed these working? Provide a defintion of purpose.
- Flask app object
The Flask app object is a core component of the Flask web application framework. It represents a Flask application instance and is responsible for handling incoming HTTP requests, routing those requests to the appropriate view functions, and returning HTTP responses to the client. In other words, the Flask app object is the entry point of a Flask application, where the application is configured and initialized. The Flask app object is working when it is successfully created and running, which means that the Flask application is up and running, and ready to receive and process incoming requests from clients.
- SQLAlchemy db object SQLAlchemy is an Object-Relational Mapping (ORM) library that provides a high-level interface for interacting with relational databases using Python code. The SQLAlchemy db object is an instance of the SQLAlchemy class, which represents a database connection and provides a high-level interface for executing database operations such as querying, inserting, updating, and deleting data. The SQLAlchemy db object is working when it is successfully connected to the target database, which means that the database connection is established, and the ORM is ready to interact with the database by executing SQL queries and mapping database tables to Python objects.
Model Definition
Define columns, initialization, and CRUD methods for users table in sqlite.db
- Comment on these items in the class, purpose and defintion.
- class User
The provided code defines a class called User that represents a user object and provides a CRUD (Create, Read, Update, Delete) interface for managing users stored in a SQLite database. The purpose of the User class is to create a model that can be used to interact with user data in the database.
- db.Model inheritance
The db.Model inheritance indicates that the class is a SQLAlchemy ORM model that will be used to interact with the database. The tablename class attribute specifies the name of the table in the database.
- init method
The init method is the constructor for the User class. It takes four parameters:name, uid, password, and dob. The name parameter is the name of the user, uid is a unique identifier for the user, password is the user's password, and dob is the user's date of birth. If the password or dob parameters are not provided, they will be set to default values.
- "@property, @
.setter"</li> </ul> The @property and @
.setter decorators are used to define getter and setter methods for the class properties. These allow the class properties to be accessed and modified like object attributes.</p> - create, read, update, delete methods
The create, read, update, and delete methods are the CRUD methods for managing user data in the database. create method adds a new user to the database, read method retrieves user data from the database, update method updates user data in the database, and delete method removes user data from the database.
- Add this Blog to you own Blogging site. In the Blog add notes and observations on each code cell.
- Change blog to your own database.
- Add additional CRUD
- Add Update functionality to this blog.
- Add Delete functionality to this blog.
Uses SQLALchemy db.create_all() to initialize rows into sqlite.db
- Comment on how these work?
- Create All Tables from db Object
For db.create_all(), the method creates all the tables defined in the SQLAlchemy models into the database. This method should be called once when initializing a new database. If the tables already exist in the database, it will not recreate them.
- User Object Constructors
The user objects are created using the User constructor. The constructor takes in parameters like name, uid, password, and dob (date of birth). This is a convenient way to create user objects with the necessary attributes.
- Try / Except
The try-except block is used to catch exceptions that may be raised when creating new objects. In this specific code, it catches the IntegrityError which occurs when the object to be created violates a unique constraint. This block ensures that if an error is raised, it will be caught, and a message will be printed indicating that the object already exists in the database.
Use of ORM Query object and custom methods to identify user to credentials uid and password
- Comment on purpose of following
- User.query.filter_by
"User.query.filter_by" is used to query the database and retrieve a specific record based on the provided filter criteria. In this case, filter_by is used to filter the records based on the _uid column, which is equivalent to filtering records based on the uid attribute of the User class.
- user.password
The "user.password" is used to retrieve the password associated with a user object. This is possible because the User class has a password attribute that corresponds to the password column in the database table.
Uses SQLALchemy and custom user.create() method to add row.
- Comment on purpose of following
- user.find_by_uid() and try/except
The purpose of user.find_by_uid() and try/except is to check if a user with the given uid already exists in the database. If a user with that uid is found, the function returns the existing user, otherwise it proceeds to create a new user.
- user = User(...)
user = User(...) creates a new User object with the provided arguments for name, uid, and password.
- user.dob and try/except
user.dob is used to store the date of birth of the new user. It is initially set to None and will be updated if a valid date is provided by the user.
- user.create() and try/except
user.create() is a custom method that is used to add a new row to the users table in the database. It takes the User object and writes it to the database using SQLAlchemy's db.session.add() and db.session.commit() methods. The try/except block is used to catch any errors that may occur during the creation of the new user object and inform the user of the error.
Uses SQLALchemy query.all method to read data
- Comment on purpose of following
- User.query.all
User.query.all() is a SQLAlchemy method that returns a list of all the User objects in the database. It's used to retrieve all the rows in a table.
- json_ready assignment, google List Comprehension
json_ready is a list of dictionaries that's created by iterating over the list of User objects (table) and calling the read() method on each object. The json_ready list comprehension uses the user.read() method to get a dictionary of each user's attributes, which can be easily converted to JSON format. The json_ready list is then returned by the read() function.
- db.Model:Inheritance - capable to make the class utilize database attributes and methods (getters and setters) - Init method instantiate an object from user class
- Setters allow attributes to be changed
- Getters enable the retrieval of a given object
""" These imports define the key objects """ from flask import Flask from flask_sqlalchemy import SQLAlchemy """ These object and definitions are used throughout the Jupyter Notebook. """ # Setup of key Flask object (app) app = Flask(__name__) # Setup SQLAlchemy object and properties for the database (db) database = 'sqlite:///cars.db' # path and filename of database app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SQLALCHEMY_DATABASE_URI'] = database app.config['SECRET_KEY'] = 'SECRET_KEY' db = SQLAlchemy() # This belongs in place where it runs once per project db.init_app(app)
from sqlalchemy import Column, Integer, Text, String, Boolean from sqlalchemy.exc import IntegrityError class Car(db.Model): __tablename__ = "cars" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, primary_key=True) _make = db.Column(db.String(255), nullable=False, unique = False) _model = db.Column(db.String(255), nullable=False, unique = False) _price = db.Column(db.Integer, nullable=False, unique = False) _year = db.Column(db.Integer, nullable=False, unique = False) _desc = db.Column(db.String(255), nullable=False, unique = True) _engine = db.Column(db.String(255), nullable=False, unique = False) _body_style = db.Column(db.String(255), nullable=False, unique = False) _owner = db.Column(db.String(255), nullable=False, unique = False) def __init__(self, make, model, price, year, desc, body_style, engine, owner): # Adding instance attributes self._make = make self._model = model self._price = price self._year = year self._desc = desc self._body_style = body_style self._engine = engine self._owner = owner # Add getters and setters for make, model, price, year @property def make(self): return self._make @make.setter def make(self, make): self._make = make @property def model(self): return self._model @model.setter def model(self, model): self._model = model @property def price(self): return self._price @price.setter def price(self, price): self._price = price @property def year(self): return self._year @year.setter def year(self, year): self._year = year @property def desc(self): return self._desc @desc.setter def desc(self, desc): self._desc = desc @property def body_style(self): return self._body_style @body_style.setter def body_style(self, body_style): self._body_style = body_style @property def engine(self): return self._engine @engine.setter def engine(self, engine): self._engine = engine @property def owner(self): return self._owner @owner.setter def owner(self, owner): self._owner = owner def dictionary(self): dict = { "make" : self.make, "model" : self.model, "price" : self.price, "year" : self.year, "desc" : self.desc, "body_style" : self.body_style, "engine" : self.engine, "owner" : self.owner } return dict def __str__(self): return json.dumps(self.dictionary) def create(self): try: # creates a Car object from Car(db.Model) class, passes initializers db.session.add(self) # add prepares to persist person object to Users table db.session.commit() # SqlAlchemy "unit of work pattern" requires a manual commit return self except IntegrityError: db.session.remove() return None # CRUD read converts self to dictionary # returns dictionary def read(self): return { "id" : self.id, "make" : self.make, "model" : self.model, "price" : self.price, "year" : self.year, "desc" : self.desc, "body_style" : self.body_style, "engine" : self.engine, "owner" : self.owner } # CRUD update: updates attributes # returns self def update(self, make="", model="", price="", year="", desc="", body_style="", engine="", owner=""): """only updates values with length""" if len(make) > 0: self.make = make if len(model) > 0: self.model = model if price > 0: self.price(price) if year > 0: self.year(year) if desc >= 0: self.desc(desc) if len(body_style) > 0: self.body_style(body_style) if len(engine) > 0: self.engine(engine) if len(owner) > 0: self.owner(owner) db.session.commit() return self # CRUD delete: remove self # None def delete(self): db.session.delete(self) db.session.commit() return None # Function to initialize the Cars def initCars(): with app.app_context(): """Create database and tables""" # db.init_app(app) db.create_all() """Data for table""" car1 = Car(make="BMW", model="2 Series", price=34000, year=2021, desc="The BMW 2 series is a stylish sports coupe that drives just as well as it looks.", body_style="coupe", engine="2.0L four-cylinder", owner="John Doe") cars = [car1] """Builds sample user/note(s) data""" for car in cars: try: car.create() except IntegrityError: '''fails with bad or duplicate data''' db.session.remove() print(f"Records exist, duplicate car, or error: {car.id}") initCars()
import sqlite3 database = 'instance/cars.db' def create(): make = input("Enter the make of the car:") model = input("Enter the model:") price = input("Enter the price:") year = input("Enter the year:") desc = input("Enter a description of the car:") body_style = input("Enter the body style of the car:") engine = input("Enter the engine type:") owner = input("Who's the owner of the car?") # Connect to the database file conn = sqlite3.connect(database) # Create a cursor object to execute SQL commands cursor = conn.cursor() try: # Execute an SQL command to insert data into a table cursor.execute("INSERT INTO cars (_make, _model, _price, _year, _desc, _body_style, _engine, _owner) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", (make, model, price, year, desc, body_style, engine, owner)) # Commit the changes to the database conn.commit() print(f"A new car has been added") except sqlite3.Error as error: print("Error while executing the INSERT:", error) # Close the cursor and connection objects cursor.close() conn.close() create()
def read(): with app.app_context(): table = Car.query.all() json_ready = [car.read() for car in table] # "List Comprehensions", for each user add user.read() to list return json_ready read()
import sqlite3 database = 'instance/cars.db' # Take the inputs for each attribute def update(): id = input("Enter the id of the car:") make = input("Enter the make of the car:") model = input("Enter the model:") price = input("Enter the price:") year = input("Enter the year:") desc = input("Enter a description of the car:") body_style = input("Enter the body style of the car:") engine = input("Enter the engine type:") owner = input("Who's the owner of the car?") # Connect to the database file conn = sqlite3.connect(database) # Create a cursor object to execute SQL commands cursor = conn.cursor() try: # Execute an SQL command to update data in a table # Trying to add dob right now... cursor.execute("UPDATE cars SET _make = ?, _model = ?, _price = ?, _year = ?, _desc = ?, _body_style = ?, _engine = ?, _owner = ? WHERE id = ?", (make, model, price, year, desc, body_style, engine, owner, id)) if cursor.rowcount == 0: # Car ID not found print(f"No id was found in the table") # Commit new data else: print(f"Car with the id {id} has been updated") conn.commit() except sqlite3.Error as error: print("Error while updating the record:", error) # Close the cursor and connection objects cursor.close() conn.close() update()
read()
import sqlite3 def delete(): id = input("Select the ID of the car you wish to remove: ") # Connect to the database file conn = sqlite3.connect(database) # Create a cursor object to execute SQL commands cursor = conn.cursor() # Validate the input try: id = int(id) except ValueError: print("Invalid input: ID must be an integer.") return try: # Use a parameterized query to prevent SQL injection c = conn.cursor() c.execute("DELETE FROM cars WHERE id = ?", (id,)) conn.commit() print(f"Row with ID {id} has been deleted.") except sqlite3.Error as e: print(f"Error deleting row with ID {id}: {e}") finally: # Close the connection cursor.close conn.close() delete()
read()