2.4a Hacks

  • 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.

Create Database

"""
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:///sports.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)

""" database dependencies to support sqlite examples """
import datetime
from datetime import datetime
import json

from sqlalchemy.exc import IntegrityError
from werkzeug.security import generate_password_hash, check_password_hash


''' Tutorial: https://www.sqlalchemy.org/library.html#tutorials, try to get into a Python shell and follow along '''

# Define the User class to manage actions in the 'users' table
# -- Object Relational Mapping (ORM) is the key concept of SQLAlchemy
# -- a.) db.Model is like an inner layer of the onion in ORM
# -- b.) User represents data we want to store, something that is built on db.Model
# -- c.) SQLAlchemy ORM is layer on top of SQLAlchemy Core, then SQLAlchemy engine, SQL
class Sport(db.Model):
    __tablename__ = 'sportss'  # table name is plural, class name is singular

    # Define the User schema with "vars" from object
    id = db.Column(db.Integer, primary_key=True)
    _sport = db.Column(db.String(255), unique=False, nullable=False)
    _sid = db.Column(db.String(255), unique=True, nullable=False)
    _comp = db.Column(db.String(255), unique=False, nullable=False)
    _outside = db.Column(db.String(255), unique=False, nullable=False)
    _ball = db.Column(db.String(255), unique=False, nullable=False)
    _contact = db.Column(db.String(255), unique=False, nullable=False)
    _team = db.Column(db.String(255), unique=False, nullable=False)
    _running = db.Column(db.Integer, unique=False, nullable=False)
    #_population = db.Column(db.Integer, unique=False, nullable=False)

    # constructor of a User object, initializes the instance variables within object (self)
    def __init__(self, sport, sid, comp, outside, ball, contact, team, running):
        self._sport = sport    # variables with self prefix become part of the object, 
        self._sid = sid
        self._comp = comp
        self._outside = outside
        self._ball = ball
        self._contact = contact
        self._team = team
        self._running = running
        #self._population = population

    # a name getter method, extracts name from object
    @property
    def sport(self):
        return self._sport
    
    # a setter function, allows name to be updated after initial object creation
    @sport.setter
    def sport(self, sport):
        self._sport = sport
    
    # a getter method, extracts uid from object
    @property
    def sid(self):
        return self._sid
    
    # a setter function, allows uid to be updated after initial object creation
    @sid.setter
    def sid(self, sid):
        self._sid = sid
        
    # check if uid parameter matches user id in object, return boolean
    def is_sid(self, sid):
        return self._sid == sid
    
    @property
    def comp(self):
        return self._comp
    
    # a setter function, allows name to be updated after initial object creation
    @comp.setter
    def comp(self, comp):
        self._comp = comp
    
    @property
    def outside(self):
        return self._outside
    
    # a setter function, allows name to be updated after initial object creation
    @outside.setter
    def outside(self, outside):
        self._outside = outside

    @property
    def ball(self):
        return self._ball
    
    # a setter function, allows name to be updated after initial object creation
    @ball.setter
    def ball(self, ball):
        self._ball = ball

    @property
    def contact(self):
        return self._contact
    
    # a setter function, allows name to be updated after initial object creation
    @contact.setter
    def contact(self, contact):
        self._contact = contact

    @property
    def team(self):
        return self._team
    
    # a setter function, allows name to be updated after initial object creation
    @team.setter
    def contact(self, team):
        self._team = team

    @property
    def running(self):
        return self._running
    
    # a setter function, allows name to be updated after initial object creation
    @running.setter
    def running(self, running):
        self._running = running

   
    def __str__(self):
        return json.dumps(self.read())

    # CRUD create/add a new record to the table
    # returns self or None on error
    def create(self):
        try:
            # creates a person object from User(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,
            "sport": self.sport,
            "sid": self.sid,
            "comp": self.comp,
            "outside": self.outside,
            "ball": self.ball,
            "contact": self.contact,
            "team": self.team,
            "running": self.running,
        }

    # CRUD update: updates user name, password, phone
    # returns self
    def update(self, sport="", comp="", outside="", ball="", contact="", team="", running=""):
        """only updates values with length"""
        if len(sport) > 0:
            self.sport = sport
        if len(comp) > 0:
            self.comp = comp
        if len(outside) > 0:
            self.outside = outside
        if len(ball) > 0:
            self.ball = ball
        if len(contact) > 0:
            self.contact = contact
        if len(team) > 0:
            self.team = team
        if len(running) > 0:
            self.running = running
        db.session.merge(self)
        db.session.commit()
        return self

    # CRUD delete: remove self
    # None
    def delete(self):
        db.session.delete(self)
        db.session.commit()
        return None
    
"""Database Creation and Testing """


# Builds working data for testing
    
# SQLAlchemy extracts single user from database matching User ID
def find_by_sid(sid):
    with app.app_context():
        place = Sport.query.filter_by(_sid=sid).first()
    return place # returns user object

# Check credentials by finding user and verify password
def check_credentials(sid, comp):
    # query email and return user record
    activity = find_by_sid(sid)
    if activity == None:
        return False
    if (activity.is_comp(comp)):
        return True
    return False

def find_by_sport(sport):
    with app.app_context():
        place = Sport.query.filter_by(_sport=sport).first()
    return place # returns user object

# Check credentials by finding user and verify password
def check_credentials(sport):
    # query email and return user record
    place = find_by_sid(sport)
    if place == None:
        return False
def initSports():
    with app.app_context():
        """Create database and tables"""
        db.create_all()
        """Tester data for table"""
        u1 = Sport(sport='Basketball', sid='Bas', comp='Yes', outside='No', ball='Yes', contact='Yes', team='Yes', running='Yes')
        u2 = Sport(sport='Football', sid='Foot', comp='Yes', outside='Yes', ball='Yes', contact='Yes', team='Yes', running='Yes')
        


        sports = [u1, u2]

        """Builds sample user/note(s) data"""
        for sport in sports:
            try:
                '''add user to table'''
                object = sport.create()
                print(f"Created new cid {object.sid}")
            except:  # error raised if object nit created
                '''fails with bad or duplicate data'''
                print(f"Records exist sid {sport.sid}, or error.")
                
initSports()
Created new cid Bas
Created new cid Foot

Create

      
#check_credentials("indi", "123qwerty")
# Inputs, Try/Except, and SQLAlchemy work together to build a valid database object
def create():
    # optimize user time to see if uid exists
    cid = input("Enter your user cid:")
    place = find_by_cid(cid)
    try:
        print("Found\n", place.read())
        return
    except:
        pass # keep going
    
    # request value that ensure creating valid object
    country = input("Enter the country:")
    continent = input("Enter the continent")
    population = input("Enter the population'")

    # Initialize User object before date
    place = Country(country=country, 
                cid=cid, 
                continent=continent,
                population=population
                )
    
    # create user.dob, fail with today as dob

  
    # write object to database
    with app.app_context():
        try:
            object = place.create()
            print("Created\n", object.read())
        except:  # error raised if object not created
            print("Unknown error cid {cid}")
        
create()
Created
 {'id': 7, 'country': 'Turkey', 'cid': 'Tur', 'continent': 'Europe', 'population': 9827465}

Read Database

def read():
    with app.app_context():
        table = Country.query.all()
    json_ready = [place.read() for place in table] # "List Comprehensions", for each user add user.read() to list
    return json_ready

read()
[{'id': 1,
  'country': 'United States of America',
  'cid': 'US',
  'continent': 'North America',
  'population': 9},
 {'id': 2,
  'country': 'England',
  'cid': 'Eng',
  'continent': 'Europe',
  'population': 331900000},
 {'id': 3,
  'country': 'Canada',
  'cid': 'Can',
  'continent': 'North America',
  'population': 38250000},
 {'id': 4,
  'country': 'Mexico',
  'cid': 'Mex',
  'continent': 'North America',
  'population': 126700000},
 {'id': 5,
  'country': 'Egypt',
  'cid': 'Egy',
  'continent': 'Africa',
  'population': 109300000},
 {'id': 6,
  'country': 'China',
  'cid': 'Chi',
  'continent': 'Asia',
  'population': 1412000000}]

Update

def update():
    # optimize user time to see if uid exists
    cid = input("Enter your cid:")
    place = find_by_cid(cid)

    if place is None:
        print(f"User {cid} is not found")
        return

    new_country = input("What is your new country: ")
    new_continent = input("What is your new continent: ")
    new_population = input("What is your new population: ")

    with app.app_context():
        try:
            place.update(new_country, new_continent, new_population)
            print(f"Cid, {cid}, has been updated with the country, {new_country}, with the continent {new_continent}, and the population, {new_population}")
        except:
            print(f"There was a problem in updating the country, {cid}")
        
update()
Cid, Tur, has been updated with the country, sdf, with the continent sdf, and the population, 234

Delete

def delete():
    # optimize user time to see if uid exists
    cid = input("Enter your cid:")
    place = find_by_cid(cid)

    if place is None:
        print(f"Country, {cid} is not found :(")

    with app.app_context():
        try:
            place.delete()
            print(f"Country, {cid} has been deleted.")
        except:
            print("Enter a country link that already exists")        
delete()
Country, Tur has been deleted.
def menu():
    operation = input("Enter: (C)reate (R)ead (U)pdate or (D)elete or (S)chema")
    if operation.lower() == 'c':
        create()
    elif operation.lower() == 'r':
        read()
    elif operation.lower() == 'u':
        update()
    elif operation.lower() == 'd':
        delete()
    elif operation.lower() == 's':
        schema()
    elif len(operation)==0: # Escape Key
        return
    else:
        print("Please enter c, r, u, or d") 
    menu() # recursion, repeat menu
        
try:
    menu() # start menu
except:
    print("Perform Jupyter 'Run All' prior to starting menu")
Created
 {'id': 7, 'country': 'Turkey', 'cid': 'Tur', 'continent': 'Europe', 'population': 9263}
Cid, Tur, has been updated with the country, lsdhdbf, with the continent sdfg, and the population, 3456
Country, Tur has been deleted.

2.4b Hacks

  • Add this Blog to you own Blogging site. In the Blog add notes and observations on each code cell.
  • In this implementation, do you see procedural abstraction?
  • In 2.4a or 2.4b lecture

    • Do you see data abstraction? Complement this with Debugging example.

      • Yes I do see data abstraction because by usuing this form of databases, we are narrowing down the code we have to use. In fact, for the users technecally we don't have to use any code. We can let the website users add their names and accounts and create all the data for us. Also, we can choose one row or column from the table to only read or alter one piece of the data.
      • Debugging

        • This piece of code creates a new user and defines it properties. This user can be updated by the update command but if this same code is run again it will override the update command
      • Debugging

        • This puts the different types of data into the table
      • Debugging

        • This code creates the properties of the table. It has setters and getters and is very important because there would be no table rows or columns without this piece of code.
      • Debugging

        • This piece of code also helps create properties. It decides if a property is going to be unique or not. So a uid would be unique because it is like a username and every user has a different username.
      • Debugging

        • This piece of code actually creates the database file
    • Use Imperative or OOP style to Create a new Table or do something that applies to your CPT project.

Reference... sqlite documentation