is52027c lab 13.h
in this lab we're going to look at flask's request object, including
- GET requests that pass some user input (i.e. a key/value pair in the url)
- POST requests submitted via a form
- basic validation
- uploading a file
- using flask's implementation of WTForms
task 1: adapting headlines for user input via GET
note: my version of this in the lab-13 repo is get_headlines.py
- in this exercise, you will adapt your headlines project from the last lab to respond to user choices made via a GET request.
- this means making use of flask's request object http://flask.pocoo.org/docs/0.12/quickstart/#the-request-object
- you will implement a simple form that allows the user to choose which rss headlines to display; bbc, aljazeera or ap (associated press)
rss feeds
you can use these or find some of your own:
- bbc: http://feeds.bbci.co.uk/news/rss.xml
- aljazeera : https://www.aljazeera.com/xml/rss/all.xml
- ap: http://hosted2.ap.org/atom/APDEFAULT/cae69a7523db45408eeb2b3a98c0c9c5
add a form
- add a super simple form to your template that uses a text field to pass a value for 'publication'
- you don't need to explicitly add method or action as they will defualt to 'GET' and 'POST' which is what we want
adapt the headlines view
- get the value of 'publication' from request.args
- fetch the headlines from that rss feed and pass them to the template
- use a default value for the case where no choice is passed
note that
request.args['publication']
will throw a key error if no value was passed.
so it's better to use
request.args.get('publication')
you check it exists, then if it does assign that value to you 'publication' variable
task 2: mocking up a login form using POST
note: my version of this in the lab-13 repo is mock_login.py
- in this task you are simply asked to mock up a login form in flask
- you need a form that submits username & password via a POST request
- you need to extract those values and check them against stored values (we will just use CONSTANTS in this case)
adding messaging
- well designed user interactions display helpful messages when something hasn't gone right
- flask helps you do this via 'message flashing' http://flask.pocoo.org/docs/0.12/quickstart/#message-flashing
- there's an example of using this with a login process at http://flask.pocoo.org/docs/0.12/patterns/flashing/#message-flashing-pattern
- you use get_flashed_messages() in the template to extract these messages for display
- flash messages use flask's session features to pass the message between a request (e.g. login attempt) and the next request (e.g. redisplaying the form with a message)
- for reasons which will be explained later, this means you need to set the value of app.secret_key (it can be anything!)
task: create helpful messages for cases where username / password are missing or wrong
task 3: uploading files
note: my version of this in the lab-13 repo is file_upload.py
- the following script will upload image files to the directory 'static/uploads'.
- you need to create that directory before running the script
- create your own version of this script
- work your way through each line in the upload_image view, making sure you understand what is going on
you should look up the path & listdir functions from the python standard library to check what they do:
you should also look up what secure_filename does: see the quickstart pages http://flask.pocoo.org/docs/0.12/patterns/fileuploads/
from flask import Flask
from flask import render_template, session, request
from flask import redirect, url_for, flash
from flask import send_from_directory
import os
from werkzeug.utils import secure_filename
ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif'])
UPLOAD_FOLDER = 'static/uploads'
app = Flask(__name__)
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
# defining allowed file types for file upload
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/')
def index():
files = [os.path.join(UPLOAD_FOLDER,f) for f in os.listdir(UPLOAD_FOLDER)]
return render_template('upload_index.html', files=files)
@app.route('/upload', methods = ['GET','POST'])
def upload_image():
if request.method == 'POST':
if 'file' not in request.files:
flash('no file part')
return redirect(request.url)
file = request.files['file']
if file.filename=='':
flash('no selected file')
return redirect(request.url)
if not allowed_file(file.filename):
flash('file type not allowed')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(UPLOAD_FOLDER,filename))
flash('File "{}" successfully uploaded'.format(filename))
return redirect(url_for('index'))
return render_template('file_upload.html')
@app.route('/download/<filename>')
def download_file(filename):
print filename
return send_from_directory(UPLOAD_FOLDER,
filename)
if __name__ == '__main__':
app.run(debug=True,host='0.0.0.0',port=8000)
task: rendering images
create a template to display your uploaded images
task 4: flask-wtforms extension
note: my version of this in the lab-13 repo is mock_login_wtforms.py
the flask extension flask-wtf implements the widely used python package, wtforms. this makes it easy to set up safe and user-friendly forms.
first you will need to install flask-wtf:
pip install --user Flask-WTF
- task: review the quickstart docs for flask-wtf and see of you can figure out how to create and validate your mock login form this way
- https://flask-wtf.readthedocs.io/en/stable/quickstart.html
- the thing to remember is that flask-wtf helps you to generate the form and to validate it.
- you can find a nice simple example / explanation at http://exploreflask.com/en/latest/forms.html
- note that the second part ('rendering forms') is halfway down that page
- don't worry about the csrf stuff at the moment! we'll go over that in the lectures
extension task: apply wtforms to file uploads
The snippets for achieving this are on https://flask-wtf.readthedocs.io/en/stable/form.html#module-flask_wtf.file
(Note that, currently, you do not have the Flask-Uploads extension installed).
keep developing this work during the week...