Python Guild

2018.03.21

Web development with Flask

Flask is simple

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

And easy to setup

pip install flask

But it's also very flexible and modular


cat requirements.txt |grep flask
flask
flask-admin
flask-sqlalchemy
flask-restful
flask-wtf
flask-login
flask-hashing

Simplicity is easy to abuse

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"
    
@app.route("/user/login")
def login():
    return "Hello World!"
    
@app.route("/user/signup")
def signup():
    return "Hello World!"
    
    
@app.route("/video/upload")
def upload():
    return "ddd"
    
@app.route("/Whatever")
def upload():
    return "ddd"
    
        
    

This can turn ugly quickly. Use blueprints!

app.register_blueprint(home, url_prefix='/')
app.register_blueprint(user, url_prefix='/user')
app.register_blueprint(video, url_prefix='/video')

DB access?


SELECT * from ??
Rather not..

Use sqlalchemy!

user = db.session.query(models.Users).filter(models.Users.name == username).first()

Create table??

No.

Use Alembic for your migrations

ALCHEMY_URL=mysql+mysqlconnector://root:emarroot@localhost:3306/porghub APP_SECRET=mydevsecret alembic upgrade head                    
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> 86bba768a6c8, Added initial tables

Server?


python app.py? 

Werkzeug is ok for development, but for prod we might need something more heavy.


UWSGI/GUNICORN


Static files?

Flask can serve static files, if you really want it, but why would you do that?
Use NGINX like you would normally
server{
listen 80;
location /static {
root /usr/src;

}
location /{
include uwsgi_params;
uwsgi_pass uwsgi:3031;

proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}

}

With time you'll need an admin interface

Why code, when you dont have to?
flask-admin

admin.add_view(MyModelView(models.Users, db.session,
column_list=['id', 'name', "description", "is_active", "is_admin"],
search_fields=['username'],
form_columns=['id', 'name', "description", "is_active", "is_admin"]))

Sessions?


session['userid'] = 'ugly'

use flask-login

user = db.session.query(models.Users).filter(models.Users.name == username).first()

if not user or user and not hashing.check_value(user.password, password, settings.SECRET):
flash("Failed to log you in with these credentials")
return render_template("login.html", form=form)

else:
#login
login_user(user)
return redirect('//')

Forms, and views

Flask-wtf
Jinja2
Template inheritance
Validations
Fun

login.html

{% extends "base.html" %}

{% block container %}

<body>
<div class = "container">
<h4>Register</h4>
<br>
{% from "_formhelpers.html" import render_field %}
<form method=post action="/user/login">
<dl>
{{render_field(form.username)}}
{{render_field(form.password)}}
<input name=_csrf_token type=hidden value="{{ csrf_token() }}">

</dl>
<p><input type=submit value=Login></p>
</form>

{% if error %}
<p class="error"><strong>Error:</strong>{{error}}</p>
{% endif %}

</div>
</body>

{% endblock %}


login form


class LoginForm(Form):
username = StringField('Username', [validators.DataRequired()])
password = PasswordField('Password', [validators.DataRequired()])

asdasdasda

By Bálint Csergő