|
|
|
## virtual server checklist
|
|
|
|
|
|
|
|
* check you can log in to your vs
|
|
|
|
* check you have git
|
|
|
|
* check you have an editor (vim, nano, emacs...)
|
|
|
|
* remember, we are using python 3; so either your commands use python3 or you have set up an alias as recommended in lab 5 http://gitlab.doc.gold.ac.uk/data-networks-web/lab-exercises/wikis/web-server
|
|
|
|
|
|
|
|
update your system:
|
|
|
|
|
|
|
|
sudo apt-get update
|
|
|
|
sudo apt-get upgrade
|
|
|
|
|
|
|
|
for more on the virtual servers see:
|
|
|
|
|
|
|
|
- http://gitlab.doc.gold.ac.uk/data-networks-web/lab-exercises/wikis/web-server
|
|
|
|
- https://www.doc.gold.ac.uk/dept/VirtualServer
|
|
|
|
|
|
|
|
## pip
|
|
|
|
|
|
|
|
is pip installed?
|
|
|
|
pip list
|
|
|
|
if not
|
|
|
|
sudo apt-get update
|
|
|
|
sudo apt-get install python-pip
|
|
|
|
|
|
|
|
pip defaults to installing Python packages to a system directory (such as /usr/local/lib/python3.4). This requires root access. --user makes pip install packages in your home directory instead, which doesn't require any special privileges.
|
|
|
|
|
|
|
|
## set up a git repo
|
|
|
|
|
|
|
|
create a git repo called term-2-lab
|
|
|
|
|
|
|
|
## install flask
|
|
|
|
|
|
|
|
* pip install --user flask
|
|
|
|
|
|
|
|
note: pip defaults to installing Python packages to a system directory (such as /usr/local/lib/python3.4). This requires root access. --user makes pip install packages in your home directory instead, which doesn't require any special privileges.
|
|
|
|
|
|
|
|
* to list installed packages: _pip list_
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## hello, world
|
|
|
|
|
|
|
|
make a directory lab-exercises
|
|
|
|
|
|
|
|
mkdir lab-exercises
|
|
|
|
cd lab-exercises
|
|
|
|
|
|
|
|
* create a hello world app.
|
|
|
|
|
|
|
|
* type it in by hand.
|
|
|
|
|
|
|
|
* read the explanation of the different lines [flask quickstart](http://flask.pocoo.org/docs/0.12/quickstart/#a-minimal-application)
|
|
|
|
|
|
|
|
## run using development server
|
|
|
|
|
|
|
|
add
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
app.run(debug=True,host='0.0.0.0',port=8000)
|
|
|
|
|
|
|
|
## port + ip
|
|
|
|
|
|
|
|
port 8000 is the port on which the virtual servers are available externally
|
|
|
|
|
|
|
|
host=0.0.0.0 makes the server externally visible
|
|
|
|
|
|
|
|
## run your app
|
|
|
|
|
|
|
|
python3 hello_world.py
|
|
|
|
|
|
|
|
visit http://doc.gold.ac.uk/usr/<your vs>
|
|
|
|
|
|
|
|
## debug mode
|
|
|
|
|
|
|
|
debug = True
|
|
|
|
|
|
|
|
http://flask.pocoo.org/docs/0.12/quickstart/#debug-mode
|
|
|
|
|
|
|
|
This does the following things:
|
|
|
|
|
|
|
|
1. it activates the debugger
|
|
|
|
1. it activates the automatic reloader
|
|
|
|
1. it enables the debug mode on the Flask application.
|
|
|
|
|
|
|
|
|
|
|
|
## routing
|
|
|
|
|
|
|
|
* add a route that prints the time right now.
|
|
|
|
* you'll need to import the datetime module
|
|
|
|
* the date & time right now is given by datetime.datetime.now()
|
|
|
|
* but flask can only return a string so you also need _str_
|
|
|
|
* if you keep refreshing this view the time should keep updating
|
|
|
|
* => you can see that flask views are dynamic
|
|
|
|
|
|
|
|
## variable rules
|
|
|
|
|
|
|
|
* add a route with a variable so that /hello/bob will return "hello, bob!"
|
|
|
|
* see [variable rules](http://flask.pocoo.org/docs/0.12/quickstart/#variable-rules)
|
|
|
|
|
|
|
|
## rss feeds
|
|
|
|
|
|
|
|
* to make things a bit more interesting, we'll write an app that shows news headlines from rss feeds.
|
|
|
|
* we'll use this again later when we look at templates
|
|
|
|
* we'll need the feedparser module
|
|
|
|
|
|
|
|
so
|
|
|
|
pip install --user feedparser
|
|
|
|
|
|
|
|
##
|
|
|
|
|
|
|
|
here's the code
|
|
|
|
|
|
|
|
from flask import Flask
|
|
|
|
import feedparser
|
|
|
|
from random import randint
|
|
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
|
|
|
BBC_FEED = "http://feeds.bbci.co.uk/news/rss.xml"
|
|
|
|
|
|
|
|
@app.route("/")
|
|
|
|
def headline():
|
|
|
|
feed = feedparser.parse(BBC_FEED)
|
|
|
|
article = feed['entries'][0]
|
|
|
|
return """<html>
|
|
|
|
<body>
|
|
|
|
<h1> BBC headline </h1>
|
|
|
|
<b>{0}</b> <br/>
|
|
|
|
<i>{1}</i> <br/>
|
|
|
|
<p>{2}</p> <br/>
|
|
|
|
</body>
|
|
|
|
</html>""".format(article.get("title"),
|
|
|
|
article.get("published"), article.get("summary"))
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
app.run(debug=True,host='0.0.0.0',port=8000)
|
|
|
|
|
|
|
|
* adapt the code to select a random headline from the first 10 in the rss feed
|
|
|
|
* you'll need the _randint_ function from the _random_ module
|
|
|
|
|
|
|
|
## module names
|
|
|
|
|
|
|
|
remember your simple app that showed the time.
|
|
|
|
|
|
|
|
what happens if you rename your app datetime.py then try to run it?
|
|
|
|
|
|
|
|
see also: the python standard library https://docs.python.org/3/library/index.html
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## jinja templates
|
|
|
|
|
|
|
|
|
|
|
|
## templates
|
|
|
|
|
|
|
|
* we know we can return html from our flask view
|
|
|
|
|
|
|
|
* but it would be better to follow 'separation of concerns' by using a templating system.
|
|
|
|
|
|
|
|
* flask uses [jinja](http://jinja.pocoo.org/)
|
|
|
|
|
|
|
|
* there's a [quick intro on the flask site](http://flask.pocoo.org/docs/0.12/quickstart/#rendering-templates)
|
|
|
|
|
|
|
|
* jinja is a general templating system for python not just for flask
|
|
|
|
|
|
|
|
* there's fuller documentation at [Template Designer Documentation](http://jinja.pocoo.org/docs/2.10/templates/)
|
|
|
|
|
|
|
|
* it is used by Instagram, amongst others
|
|
|
|
|
|
|
|
## render_template
|
|
|
|
|
|
|
|
* to render a template you can use the render_template() method.
|
|
|
|
|
|
|
|
* flask will look for templates in the templates folder
|
|
|
|
|
|
|
|
* see http://flask.pocoo.org/docs/0.12/quickstart/#rendering-templates
|
|
|
|
|
|
|
|
## try it
|
|
|
|
|
|
|
|
* try creating a template for one of your mini-apps
|
|
|
|
|
|
|
|
* pass it a variable, which is rendered in the template as {{ variable }}
|
|
|
|
|
|
|
|
for example
|
|
|
|
|
|
|
|
@app.route('/hello/<name>')
|
|
|
|
def hello(name=None):
|
|
|
|
return render_template('hello.html', name=name)
|
|
|
|
|
|
|
|
|
|
|
|
## autoescaping
|
|
|
|
|
|
|
|
using jinja with flask helps tackle XSS because autoescaping is enabled for all templates ending in .html, .htm, .xml as well as .xhtml when using render_template()
|
|
|
|
|
|
|
|
## other variables
|
|
|
|
|
|
|
|
other variables which are available in jinja include
|
|
|
|
|
|
|
|
* config: The current configuration object (flask.config)
|
|
|
|
|
|
|
|
* request: The current request object (flask.request). This variable is unavailable if the template was rendered without an active request context.
|
|
|
|
|
|
|
|
* session: The current session object (flask.session). This variable is unavailable if the template was rendered without an active request context.
|
|
|
|
|
|
|
|
* get_flashed_messages(): The flask.get_flashed_messages() function.
|
|
|
|
|
|
|
|
we'll be covering these as part of flask over the next few weeks.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## jinja objects
|
|
|
|
|
|
|
|
all of the basic Python data structures, such as variables, objects, lists, and dictionaries, can be understood by
|
|
|
|
jinja and can be processed in a very similar way.
|
|
|
|
|
|
|
|
To output the result of a function in a template, just call the function as any regular Python function.
|
|
|
|
|
|
|
|
## loops
|
|
|
|
|
|
|
|
* jinja includes 'if' and 'for' loops.
|
|
|
|
|
|
|
|
the format of for loops is like this:
|
|
|
|
|
|
|
|
{% for article in articles %}
|
|
|
|
<b>{{article.title}}</b><br />
|
|
|
|
<p>{{article.summary}}</p>
|
|
|
|
{% endfor %}
|
|
|
|
|
|
|
|
|
|
|
|
## rss feeds
|
|
|
|
|
|
|
|
* create a template that loops over the news items from the bbc's rss feed
|
|
|
|
|
|
|
|
* you need to pass the articles to the template via render_template so it can loop over them
|
|
|
|
|
|
|
|
|
|
|
|
## 'if' statement
|
|
|
|
|
|
|
|
* in jinja, 'if' statements take the form
|
|
|
|
|
|
|
|
{% if <condition>}
|
|
|
|
<display something>
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
* add an if statement to only display an rss feed if it contains a certain word
|
|
|
|
|
|
|
|
you can use
|
|
|
|
|
|
|
|
if <word> in article.summary
|
|
|
|
|
|
|
|
remember, words could have uppercase or lowercase letters. how do you make sure you only need to test for one case?
|
|
|
|
|
|
|
|
|