Posted on

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.

  1. set up is where we do our app configuration and define all our views etc, essentially building our app instance.
  2. 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:

  1. construct with xhr =new XMLHttpRequest()
  2. initialize/configure with xhr.open(<"GET"/"POST">, <URL>, [optional: async, user, password])
  3. set up callbacks for:
    • xhr.onload = function executes on completion of request
    • xhr.onerror = function executes if request couldnt be made
    • xhr.onprogress = function(event) executes periodically with an event object containing download progress information
  4. send the request xhr.send(<request body>) (can be empty, like if we're doing a get request)
  5. callbacks execute
  6. read response data from object attributes such as xhr.status which holds an http status code such as 200 or 404.

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 codemeaning
0initial state, object just was just created
1request has been initialized/configured by calling xhr.open()
2response headers received
3response is loading (set every time we receive a data packet)
4request 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.

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

htmldescription
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-mutedgreyed out text
.text-successgreen text for success messages
.text-dangerred text for errors etc
.bg-dangerred 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()