Flask
Python web frameworks Django Roughly follows MVC pattern Steeper learning curve. Flask Initially an April Fools joke Micro -framework: minimal approach. Smaller learning curve http://flask.pocoo.org/docs/0.12/quickstart/#a-minimalapplication
Setting up Flask on your Ubuntu VM sudo apt-get update y sudo apt-get install python3-pip virtualenv -y # Create a local version of Python environment (see next slide) mkdir hw2 cd hw2 virtualenv -p python3 env source env/bin/activate pip3 install flask # edit web application files in this directory (e.g. app.py) # then run python app.py
virtualenv A way to create an instance of Python for you to install applications specific to your application Within hw2 directory: virtualenv env Creates a directory called env that will hold all modules you install (i.e. your environment) source env/bin/activate Sets up the shell to use the environment in env Must be done everytime you want to run your app pip3 install flask Installs flask into your Python virtual environment Or if a file requirements.txt provided: pip3 install r requirements.txt Installs all packages specified in file Note: to ensure that the env directory is not included in your repository add a.gitignore file in the top-level of your repository that includes env e.g. echo "env" >!.gitignore
Flask directory structure Convention: (assuming app.py stored in hw2) hw2/ static/ Directory holding static content (e.g. images, regular HTML) templates/ Directory holding Jinja2 HTML templates
Hello world app.py Create app as a Flask object Use route() method of Flask with parameter '/' to wrap a function that will return a page when the URL is accessed When called directly by python, use the run() method of Flask to launch the web app on all IP addresses of the host using port 8888 Not run when integrated with apache2/nginx WSGI
Flask views Ways of presenting pages that URLs route to MethodView defines views per HTTP request method based on a URL pattern Decoupling allows a view to be used for multiple routes Added later in development
REPL Python/Flask app https://bitbucket.org/wuchangfeng/cs410c-src/ WebDev_Repl_FlaskBasics Read-Evaluate-Print-Loop for Python Demo
app.py MethodViews stored in main.py, repl.py and test.py Routes added for '/', '/repl/', and '/test/' Named per URL endpoint via as_view When url_for method called on named view, the URL is returned
main.py (Part 1: get) MethodView for Main defines view for GET on '/' Calls built-in render_template class method in Flask to render Jinja2 template
templates/index.html Jinja2 template for main page Leverages Flask's session object to get username if authenticated Uses name from as_view to retrieve URL for form action ('/') Implements a POST Logout if logged in Username and Password if not logged in
A word about Jinja2 templates Base page is like a base class Sub pages are like derived classes Example Base page layout.html Base page layout.html
main.py (Part 2: post) MethodView for Main also defines view for POST on '/' Logout processed if corresponding form button pressed Process login (ensure username and passwd given) Grab form fields submitted and check credentials Create a session with username supplied if successful and redirect to Use Flask's redirect method to reload URL for index view ('/')
util.py Defines login_required function as a decorator via functools.wraps() Wraps other functions in app to ensure authenticated use
templates/repl.html Form submission for executing commands repl.py Python for executing command given in form login_required decorator, eval expression (never use!)
Flashed messages Mechanism for sending status or error messages into a Jinja2 template
Guestbook Python/Flask app https://bitbucket.org/wuchangfeng/cs410c-src WebDev_Guestbook_sqlite3 Guestbook backed by sqlite3 database Simple monolithic MVC app Model and Controller in main.py View in templates (Does not use Flask's View support)
main.py (model) Has select() and insert() methods For hw2 implement both but deliver via dictionary (does not persist upon script termination)
main.py Controller has 3 routes index() uses select() method in model to populate dictionary to send to template to list guestbook entries sign() uses insert() method in model to insert new entry into database from form
News Article Python/Flask app https://bitbucket.org/wuchangfeng/cs410c-src WebDev_NewsArticles_MVP MVP, MySQL example Defines a base class for model (specify interface) Derive model implementations from it In-memory dictionary (hw2) File system Sqlite3 (hw3) MySQL Eventually, App Engine DataStore (hw5)
app.py Contains routes from URLs to individual Presenters
app.py Some routes require being logged in
IModel.py Defines an abstract data type for model Methods that must be supported, their parameters, and return values Specific instantiation for MySQL in model.py Define abstract method fetchall()
IModel.py Define abstract methods art() and add_art()
model.py (specific model for MySQL) Initialize MySQL Implement fetchall() Implement art() and add_art()
presenter.py Provide views based on presenter function Interface with model object given in constructor Example: articles() uses model method self.model.fetchall() Pass to template
presenter.py add_article and single article presenter leveraging model methods add_art() and art() before passing to template
Homework
Preview Homework #2-5 Incremental construction of a scalable CS course review web site HW #2: Simple Python Flask MVP web app with hardcoded reviews HW #3: Add sqlite3 database, read/create/delete HW #4: Containerize web app, deploy on Compute Engine HW #5: Adapt Model and deploy on Platform-as-a- Service (AppEngine, AppEngine datastore)
Homework #2 Create a toy Python Flask web application for viewing (and eventually submitting) anonymous reviews of courses Within private repository, create a directory "hw2" for your application Application should follow an MVP pattern and support two routes/views initially Default landing page Page for reading all reviews Application should create an abstract data model that serves as the base class for specific instantiations (Python dict, sqlite3, AppEngine, etc) Abstract model should be documented as shown in News Article app Model should support fields that a course review would typically have Term offered, year offered, time of the week offered, instructor, review, rating, etc. For Homework #2, model data may be hard-coded within model script as a Python dictionary (will add functionality later) Application should listen on port 8000 Submit via Bitbucket Ensure changes are committed frequently
Deployment
Production web applications Python/Flask development server *not* built for performance Static files not handled efficiently Typically, integrated with a production web server that serves static content e.g. apache2 or nginx
WSGI Web Server Gateway interface (similar to old-school cgi interface) Standard that specifies communication between apache2/nginx and a web application Implementations include uwsgi, mod_wsgi, and gunicorn Takes the place of mod_python in apache2 Effectively a reverse-proxy that routes incoming requests to appropriate web application destination
Pictorial representation (adapted from realpython.com)
CS 201 Tutoring Python/Flask app https://bitbucket.org/wuchangfeng/cs410c-src WebDev_itscs201 Google Compute Engine /etc/nginx/sites-available (sites-enabled) /etc/nginx/sites-available/itscs201 /etc/uwsgi/sites-available (sites-enabled) /etc/uwsgi/sites-available/itscs201.ini
server { listen 80; server_tokens off; server_name itscs201.oregonctf.org; root /var/www/html/itscs201/www; location / { include uwsgi_params; uwsgi_pass unix:///tmp/itscs201.sock; } location /static { alias /var/www/html/itscs201/www/static; } } ## Only requests to our Host are allowed if ($host!~ ^(oregonctf.org itscs201.oregonctf.org)$ ) { return 444; }
Example itscs201 Install script (install_nginx.sh) Install packages Configure nginx with sites-available, sites-enabled Configure uwsgi with apps-available, apps-enabled, and a domain socket to communicate to nginx Restart services Optionally, obtain a Let's Encrypt cert # sudo add-apt-repository ppa:certbot/certbot -y # sudo apt-get update # sudo apt-get install certbot python-certbot-nginx -y # sudo certbot --nginx