Table of Contents
flask
flask is a framework used for building web apps. it uses the jinja template engine
It primarily operates via an app
object.
flask is built on the WSGI spec, what this means is that the server hardware is running a WSGI server, that server receives an HTTP request, transforms it into a WSGI environ dict, calls a WSGI application (flask) with that environ dict, the application processes the dict and returns a WSGI response which the server translates to an HTTP response and sends it to the client.
what this means is that we never actually touch a raw request we simply set up responses for different cases our flask app might get.
Flask also makes use of the jinja template engine and the workzeug module to provide a bunch of handy functionality such as input sterilization.
We can connect our own database layer but flask doesn't come with one. That said, there is a version of SQLAlchemy, a popular database abstraction layer, preconfigured to work with flask called `Flask-SQLAlchemy
objects
app
the app object represents the WSGI application the server will call with a request dict. It holds all the configuration information and all the request handlers.
request
represents the request dict. Stores query string variables and cookies. Access query vars with request.args
and cookies with request.cookies
. Both are stored as dictionaries. It's reccomended to use request.cookies.get("key")
to avoid keyerrors. Access request form data with request.form["field_name"]
. to access JSON data we use request.json["field_name"]
session
Holds user specific data between requests. we can add and remove data from it. An example would be adding a username to the session on login.
The session object is serialized into a cookie on the client, so you have to be conscious of size to avoid truncating it. The session cookie is encrypted with the secret key that you can configure in flask.
g
this is a proxy object for you to store stuff in that can then be acessed by any function in the app, it does not persist between instances. You can set a new member simply by doing g.foo = data
.
blueprint
a blueprint is essentially a middle layer between an app and some views. It allows you to group a bunch of related views together into one blueprint which can then be added to the app. as far as writing views for a blueprint is concerned it exposes an identical interface as the app object. to integrate a blueprint into the app use
def create_app():
from . import blueprint_name #your blueprint is defined in blueprint_name.py
app = Flask(__name__, instance_relative_config=True)
app.register_blueprint(blueprint_name.bp)
return app
To initialize a blueprint in your blueprint_name.py
file:
bp = Blueprint('blueprint_name', __name__, url_prefix='/url_prefix')
application phases
this is analogous to compile time and run time. In the set up phase we are defining our routing and logic etc. In the serving phase we the programmer do nothing. Our flask app should not be self modify and flask should error if we try to make it do so.
- set up is where we do our app configuration and define all our views etc, essentially building our app instance.
- serving is our run time when the flask app object we created is receiving requests
set up
we need to configure the app object with a couple things:
- the name of the file
- a secret key for session data
- a path to a db
app = Flask(__name__, instance_relative_config=True)
creates the Flask instance.
__name__
is the name of the current Python module. The app needs to know where it’s located to set up some paths, and __name__
is a convenient way to tell it that.
instance_relative_config=True
tells the app that configuration files are relative to the instance folder. The instance folder is located outside the app package and can hold local data that shouldn’t be committed to version control, such as configuration secrets and the database file.
views
these are either functions or classes bound to a url. See routing.
directory structure
The flask app crawls its local directory looking for templates and static files to include. a typical structure looks like:
project_dir/
|
+- app/
| |
| +- templates/
| +- static/
| +- __init__.py
| +- app.py
|
+- tests/
|
+- venv/
request handling
routing
by placing a decorator on a function we can bind a part of the app object's request interface to that function as a request handler.
we can include parameters in the route path using /<foo>
then binding to a function that takes foo
as an arg.
we can also bind post requests with a decorator
instead of returning raw http we can return the result of a render_template('template.html', foo='bar', baz='bat')
call
HTTP methods in routes
specify what methods a route supports with @app.route('/', methods=['GET','POST'])
. Note that 'GET'
is the default and methods is always a list. We can specify the method in the function body with if request.method == 'POST':
We can also do @app.get('/')
and @app.post('/')
to have separate functions for common http methods.
reading query strings
Query strings are what comes after a ?
in a url, for example site.com/query/?foo=0&bar=something
we can then access these in flask via request.args
.
Models with SQLAlchemy
SQLAlchemy is a python abstraction layer on top of SQL, it allows us to interact with an SQL database only using python. SQLAlchemy's interface is handled through a database
object. We initialize the database by defining model classes that represent the table structure and then calling db.create_all()
to make the tables in the actual sql database. We then interact with the database using the database.session()
onject Like with mysqlconnector we then query the database with database.session.execute(command)
followed by database.session.commit()
which guarantees all changes are made before moving on to the next piece of code.
Models
Models are essentially a way of representing data tables with object orientation, referred to as ORM (Object Relational Mapping).
Sessions
Sessions are how we interact with the database object. It represents a queue of commads we've sent and we can ensure they're all executed using the commit()
method, which blocks until the last query is completed.
JSON
gets returned if we send back a data object
authentication and verification
this can be done with workzeug or
hosting
to run the app locally use flask --app foo run
. to host on the local network add --host 0.0.0.0
jinja
the three types of placeholders are:
{% statement %}
{{expression}}
{# comment #}
{{ foo.bar }}
and{{ foo['bar'] }}
are equivalent. you can escape using{%raw%} ... {%endraw%}
or{{ '{{' }}
.
The big power of templates is that it enables code reuse and parametric page generation. Meaning we can set up a template for the main page structure including our nav bar and footer and then load in different content for every page. We can also make a macro that represents a small component we can reuse multiple times a page or reuse in multiple pages across the site. We also have filters which are like fucntions.
The prime functionality of jinja is template blocks. Each block has a scope and expressions cannot climb out of their local scope unless the block is declared with a scoped
modifier like {%block foo scoped%}
.
We pass data to jinja via keyword arguments to flask's render_template
function, which we can then access by name.
render_template("test.html", data="foo")
and then accessed by the keyword name {{data}}
Objects in the "standard flask context" are also accessible from within jinja, most importantly session
, request
and, g
. We can then key into object by for example doing {{session['username']}}
.
include
renders the entire included template
import
{% import "macros.html" as macros%}
adds declarations into scope, useful for macros
inheritance
First we define a base template. Inside the template we define blocks for a child template to override.
{% block foo %}
default content
{% endblock %}
In our child template we inherit from another template via {% extends "foo.html" %}
. We then redefine the blocks to overwrite
{% block foo %}
new content
{% endblock %}
we can also keep the old default behaviour by calling \{\{super()\}\}
inside our new block.
macros
{% macro input(name, value='', type='text', size=20) -%}
<input type="{{ type }}" name="{{ name }}" value="{{
value|e }}" size="{{ size }}">
{% endmacro %}
<p>{{ input('username') }}</p>
<p>{{ input('password', type='password') }}</p>
filters
we can call filters a number of ways:
{{var|filter1|filter2}}
{{filter2(filter2(var))}}
{% filter filtername%}
content to be filtered
{% endfilter %}
iterating over lists
{% for item in items %}
<p>item</p>
{% endfor %}
MYSQL
I WILL BE USING MARIADB SINCE THAT'S WHAT ARCH LIKES
on arch you must start he server using systemctl start mysqld
before connecting to the server with the mariadb
command. By default mariadb stores its files in a default directory like usr/mysql/
. The root user will have the same log in as the root computer account. You can use mariadb as root by doing sudo mariadb
SQL is a relational database system. It uses tables where every row is a record and every column is a field. We can then set up relations between tables in a database. Meaning we link the rows of one table to the rows of another.
SQL commands
-- SQL syntax order is:
SELECT _ FROM _ JOIN _ ON _ WHERE _ GROUP BY _ HAVING _ ORDER BY _ UNION
sometimes you may need to select a database by running use db_name;
you can then select a different database later or quit the whole session to go back to having non selected.
setting up a new user
create user 'name'@localhost identified (with <policy>) by 'password';
grant <privileges> on <db> to 'name'@localhost (with grant);
privileges are stuff like create
, alter
, drop
, insert
, update
, delete
.
linking tables
we use joins to link tables. The join returns a new table with records concatenated based on some foreign key, for example customer IDs from the customer table and customer IDs from the order table.
select orders.order_id, customers.customer_name, orders.date from
orders join customers on orders.customer_id = customers.customer_id;
using left or right join returns all the records of the left or right table even if there is nothing to join it to.
we can also union two tables or selects together using either union
or union all
to include duplicates.
a field we can join on is referred to as a key. A primary key is a unique value to identify a certain record, something like customer_id
in the customer
table and a foreign key is something like the customer_id
field in the orders
table that we can use to link orders to customers.
creating tables
create table name (
column_name TYPE CONSTRAINT,
column_name2 TYPE CONSTRAINT,....
);
some examples of types are text
, integer
, date
. Some constraints are primary key
, auto_increment
, not null
.
entering data
We add data to a table using
insert into table_name (column1, column2, ...) values (value1a, value2a, ...), (value1b, value2b, ...);
where the column tuple indicates which fields the values are tied to, and each value tuple is a new record to be inserted.
getting data
The fundamental way to query data is with the select _ from table
command. We can select everything using select * from table
or we can do select field1, field2,... from table;
to only return the data from certain fields rather than the whole row. We can use select distinct name from employees;
to get all the unique names of employees. But what if we want to filter out whole rows using where
. For example select name from friends where name like 'j%';
to get all friends whose name starts with J.
You can concatenate columns in your query by doing
select lastname + ',' + firstname as fullname from friends;
updating data
we update the structure of a table using the ALTER
keyword. To update records we use the UPDATE
and SET
keyword filtered using WHERE
.
ALTER
lets us add and remove columns to a table or rename them, for example:
alter table customers
add email text(50);
alter table customers
drop column email;
alter table customers
rename column f_name to full_name
To update records do:
uodate customers
set lastname = "hapsburg", city = "berlin"
where customerID = 1;
deleting data
we can delete a table by doing drop table table_name
we can also clear all the data from a table via truncate table table_name
. To remove specific records from a table use delete from table_name where column_name=value
creating procedures
An unparametrized procedure:
create procedure getCustomerIds as
select id from customers
go;
exec getCustomerIds;
a parametrized procedure
create procedure getIdsByNameAndCity
@name text,
@city text
as
select id from customers
where city = @city and name = @name
go;
exec getIdsByNameAndCity @city=seattle, @name = henry;
you can set specific data to be returned using the output
keyword
create procedure getIdsByNameAndCity
@name text,
@city text,
@output_data output
as
select id from customers
where city = @city and name = @name
go;
exec getIdsByNameAndCity @city=seattle, @name = henry;
connecting to the server
import mysql.connector
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword"
)
print(mydb)
executing on the server
To do stuff on the server we use an object called a cursor cursor = mydb.cursor()
then we execute sql with cursor.execute("SQL CODE")
. The data returned from the query will be stored in cursor
as an iterator, we use cursor.fetchall()
to see everything. If we modify the databse in anyway we then have to commit the change using connection.commit()
.
Javascript http requests
in order to build extra functionality into our website we may need to make our webpage do calculations that need execution on the server side, to accomplish that, we use javascript to send an http request to the server and display the response. We can use the fetch
function or aXMLHttpRequest
object. Fetch is newer but not yet featureful enough to deprecate the request object.
note that refreshing a page in javascript is finicky so if you want changes to update the whole page rather than a specific element after the request is sent its best to send the request using a form submission, either via html with <form method="POST" action="url">
or by overriding the submit button in javascript if we want to enrypt the data client side first, for example. After encrypting the data we can then call form.submit()
. Note, that if using form.submit()
we need to make sure we've updated the form data or are using a hidden form with the encrypted data.
XMLHttpRequest object
the XMLHttpRequest
object represents the request across its full lifetime, first we build the request into the object, then we send it, then we read the response from the request object's attributes. We can also read the request's progress before it's complete using a callback.
steps of use:
- construct with
xhr =new XMLHttpRequest()
- initialize/configure with
xhr.open(<"GET"/"POST">, <URL>, [optional: async, user, password])
- set up callbacks for:
xhr.onload = function
executes on completion of requestxhr.onerror = function
executes if request couldnt be madexhr.onprogress = function(event)
executes periodically with an event object containing download progress information
- send the request
xhr.send(<request body>)
(can be empty, like if we're doing a get request) - callbacks execute
- read response data from object attributes such as
xhr.status
which holds an http status code such as200
or404
.
note in step 2 if we set async to false, execution will pause until the request response is received after we send it.
sending data in a request
We now know how to make a request, but how should we include data in that request?
url
We can use the url as a variable and simply request a url that the server then does a calculation on. For example we can make a request to site.com/math/sin/<number>
and the server will respond with the sin of <number>
.
querystring
site.com/math/addition?x=<m>&y=<n>
request body
When we send a request we can send it with a jason or form data body.
xhr.send(JSON.stringify({field1: "foo", field2: "bar"}))
xhr.send(new FormData(document.querySelector("#form")))
readystate
the xhr.readystate
attribute represents the request state.
state code | meaning |
---|---|
0 | initial state, object just was just created |
1 | request has been initialized/configured by calling xhr.open() |
2 | response headers received |
3 | response is loading (set every time we receive a data packet) |
4 | request complete, response fully loaded |
we can then set up a callback for xhr.onreadystatechange = function that handles each state. |
response type
we can request the server send its response in a specific format via xhr.respoonseType
, our options are:
"text"
(this is the default )"arraybuffer"
(binary data)"blob"
"document"
(xml,html, etc)"json"
bootstrap
Bootstrap is premade css and js that implements a whole bunch of common design patterns. By including it in your html document you can rapidly flesh out and prototype a useable website without having to build your buttons, forms, etc from scratch. The base document with bootstrap should look like:
<!doctype html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
</head>
<body>
{{content}}
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" crossorigin="anonymous"></script>
</body>
to style elements bootstrap coms with a bunch of prebuilt classes, for example to make a button look like a button we might do <button type="button" class="btn btn-primary">click here!</button>
Ideally we don't need to write any css we just compose bootstrap classes for example <div class="jumbotron text-center">centered large text</div>
.
We can also cheat a little bit and use prebuilt themes from other people.
All responsive webdesign really means is that everything is defined relative to the display dimensions so that its always legible. Mobile first means that it prioritizes and is developed for use on phones, with the larger displays largely derived from the mobile design.
Layout classes
At its core Bootstrap is a resonsive, mobile first framework. We use container classes that embed behavior and relations between content blocks. For example having a top bar above a column layout.
containers
.container
is a fixed width container meaning it sticks to a set dimension.
.container-fluid
is full width meaning it expands to fill the space its given.
the grid
Bootstrap is built around a 12 column grid system. These columns can then be merged to make larger cells, they dont have to be evenly divided. to divide the grid we do
<div class = "row">
<div class = "col-x"></div>
<div class = "col-y"></div>
<div class = "col-z"></div>
</div>
where x
, y
, z
add up to 12. Note that we can have up to 12 columns and arbitrary rows.
widgets
icons
theres a lot of icons and glyphs built into bootstrap. most of them are accessible via glyphicon-<glyph>
applied to an empty span or other object.
dropdowns
Bootstrap also has dropdowns and stuff prebuilt using a combination of js functions and css.
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Dropdown Example
<span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a href="#">HTML</a></li>
<li><a href="#">CSS</a></li>
<li><a href="#">JavaScript</a></li>
</ul>
</div>
buttons
We have .btn
as our basic and stuff like .btn-success
and btn-danger
as extensions. We can modify the button with btn-block
and active
/ disabled
and btn-lg/sm/xs
.
tables
HTML already comes with markup for tables but bootstrap comes with extra classes to define table styles and behavior. .table
is the base class and some of the extensions are table-striped
and table-compact
. The tables also have highlighting classes like .success
, .danger
etc.
forms
There's not really much to say in terms of styling but we have classes that control layout form-inline
and vertical is the default. We can build nicer inputs using input groups.
<form class="form-inline">
<div class = "input-group">
<span class = "input-group-addon"><i class = "glyphicon glyphicon-user"></i></span>
<input id = "user" class = "form-control" name="user">
</div>
</form>
styling classes
Bootstrap implements all of htmls semantic markup as well as extending it with additional classes largely geared towards alerting the user and communicating status alerts.
some notable examples are
html | description |
---|---|
highlights cenclosed text | |
highlights and uses monowidth fonts, meant to be used to diplay hotkeys | |
| monowidth font with background and color change, used for code snippets |
blockquote | |
verbatim environment | |
.text-muted | greyed out text |
.text-success | green text for success messages |
.text-danger | red text for errors etc |
.bg-danger | red background |
js tools
python knowledge
decorators
Decorators are synctactic sugar on wrapper functions. If you write a function wrap:func -> func
that takes a function as an argument and returns a function that does some stuff, then calls the argument function, then does some stuff, then it can be used as a decorator.
def wrap(f):
def wrapped(*args):
print("preamble")
f(*args)
print("postamble")
return "wrapped"
return wrapped
@wrap
def foo(bar):
print(bar)
return "foo"
foo("amble")
#prints: preamble // amble // postamble as expected
#returns "wrapped"
mysqlconnector
all you really need to know is:
connection = mysql.connector.connect(user="", password="", host = "")
cursor=connection.cursor()
cursor.execute("sql query")
cursor.commit()
data = cursor.fetchall()
connection.close()