37
CIS 192: Lecture 10 Web Development with Flask Lili Dworkin University of Pennsylvania

CIS 192: Lecture 10 Web Development with Flask

  • Upload
    others

  • View
    3

  • Download
    0

Embed Size (px)

Citation preview

Page 1: CIS 192: Lecture 10 Web Development with Flask

CIS 192: Lecture 10Web Development with Flask

Lili Dworkin

University of Pennsylvania

Page 2: CIS 192: Lecture 10 Web Development with Flask

Last Week’s Quiz

req = requests.get("http://httpbin.org/get")

1. type(req.text)

2. type(req.json)

3. type(req.json())

Page 3: CIS 192: Lecture 10 Web Development with Flask

Last Week’s Quiz

req = requests.get("http://httpbin.org/get")

1. type(req.text)

<type ’unicode’>

2. type(req.json)

<type ’instancemethod’>

3. type(req.json())

<type ’dict’>

Page 4: CIS 192: Lecture 10 Web Development with Flask

Last Week’s Quiz

>>> def hi():

... return 0

...

>>> hi

<function hi at 0x1003bbc08>

>>> hi()

0

>>> type(hi)

<type 'function'>>>> type(hi())

<type 'int'>

Page 5: CIS 192: Lecture 10 Web Development with Flask

Last Week’s Quiz

>>> class Foo():

... def bar(self):

... return 0

...

>>> f = Foo()

>>> f.bar

<bound method Foo.bar of <__main__.Foo instance at 0

x1003caef0>>

>>> f.bar()

0

>>> type(f.bar)

<type 'instancemethod'>>>> type(f.bar())

<type 'int'>

Page 6: CIS 192: Lecture 10 Web Development with Flask

Last Week’s Quiz

1. type(json.dumps(json.loads('{"key": "val"}')))2. type(json.loads(json.dumps(0)))

Page 7: CIS 192: Lecture 10 Web Development with Flask

Last Week’s Quiz

1. type(json.dumps(json.loads('{"key": "val"}')))<type ’str’>

2. type(json.loads(json.dumps(0)))

<type ’int’>

Page 8: CIS 192: Lecture 10 Web Development with Flask

Last Week’s Quiz

I JSON isn’t a “type”

I JSON is a “format” – so strings can be valid JSON or notI json.dumps

I Input: Python data structure consisting of dicts, lists, ints,strings, or bools

I Output: String

I json.loadsI Input: String in valid JSON formatI Output: Python data structure

Page 9: CIS 192: Lecture 10 Web Development with Flask

Last Week’s Quiz

>>> json.dumps([1, 2, 3])

'[1, 2, 3]'>>> json.dumps(0)

'0'>>> json.dumps('a')'"a"' # note the double quotes

>>> json.dumps(f)

TypeError: <__main__.Foo instance at 0x1003caef0> is

not JSON serializable

Page 10: CIS 192: Lecture 10 Web Development with Flask

Last Week’s Quiz

>>> json.loads('[1, 2, 3]')[1, 2, 3]

>>> json.loads('0')0

>>> json.loads('a')ValueError: No JSON object could be decoded

>>> json.loads("a")

ValueError: No JSON object could be decoded

>>> json.loads('"a"')u'a'

Page 11: CIS 192: Lecture 10 Web Development with Flask

Last Week’s Quiz

Return the content type of a response object called req.

Page 12: CIS 192: Lecture 10 Web Development with Flask

Last Week’s Quiz

Return the content type of a response object called req.req.headers[’content-type’]

Page 13: CIS 192: Lecture 10 Web Development with Flask

Last Week’s Quiz

What is the main difference between GET and POST requests?

Page 14: CIS 192: Lecture 10 Web Development with Flask

Last Week’s Quiz

What is the main difference between GET and POST requests?GET requests send parameters in the URL.POST requests send parameters in the body.

Page 15: CIS 192: Lecture 10 Web Development with Flask

Last Week’s Quiz

Why does it matter?

I The server can see the data regardless of whether it is in theURL or the body.

I And if someone intercepts your package, so can they.

I But GET requests remain in browser history and can becached and bookmarked, so you want to avoid that withsensitive data.

I If you send information in the headers of your GET request,that’s “safe” (as long as you are over SSL).

I Point of the story: use GET for retrieving, POST for sending.

Page 16: CIS 192: Lecture 10 Web Development with Flask

Last Week’s Quiz

l = [lambda x: x + i for i in range(5)]

1. type(l)

2. l[0](0)

Page 17: CIS 192: Lecture 10 Web Development with Flask

Last Week’s Quiz

l = [lambda x: x + i for i in range(5)]

1. type(l)

<type ’list’>

(My typo: I really wanted type(l[0]) – what is that?)

2. l[0](0)

4

I i is a name, and throughout the loop it is being pointed atsuccessively higher integers

I When we refer to i, we get what it currently points to

Page 18: CIS 192: Lecture 10 Web Development with Flask

Web Frameworks

I We’ve been talking about making HTTP requests

I What about serving them?

I Flask is a “microframework” – small and simple, and you cansee how and why everything is happening

I Django is the “big guy on the block” – more fully featured,but also more black magic / mysterious

Page 19: CIS 192: Lecture 10 Web Development with Flask

Hello World

from flask import Flask

app = Flask(__name__)

@app.route('/')def hello_world():

return "Hello World!"

if __name__ == '__main__':app.run()

prompt$ python flask.py

* Running on http://127.0.0.1:5000/

Page 20: CIS 192: Lecture 10 Web Development with Flask

Hello World

app = Flask(__name__)

I When we create an instance of the Flask class, the firstargument is the name of the application’s module or package

I When using a single module, use __name__ because this willwork regardless of whether __name__ equals ’__main__’ orthe actual import name

Page 21: CIS 192: Lecture 10 Web Development with Flask

Hello World

@app.route('/')def hello_world():

return "Hello World!"

I The app.route('/') decorator tells Flask to call thehello_world() function when the relative url ’/’ is accessed

I The hello_world() function returns the web page (in thiscase, a simple string) to be displayed

Page 22: CIS 192: Lecture 10 Web Development with Flask

Hello World

app.run()

I The app.run() function runs the application on a local server

I This will only be visible on your own computer! We will talkabout deployment later

Page 23: CIS 192: Lecture 10 Web Development with Flask

Debugging

I When testing, use app.run(debug=True)

I Now the server will reload itself on code changes

I Additionally, you will see error messages in the browser

I But never leave this on in production!

Page 24: CIS 192: Lecture 10 Web Development with Flask

More Routing

@app.route('/bad')def bad():

return 'hi' + 4

@app.route('/bye')def bye_world():

return "Bye World!"

Page 25: CIS 192: Lecture 10 Web Development with Flask

Variable Rules

I To add variable parts to a url, use <variable_name>

I The variables are passed as arguments to the function

@app.route('/user/<username>')def greet_user(username):

return "Hello %s!" % username

Page 26: CIS 192: Lecture 10 Web Development with Flask

Variable Rules

Multiple urls can route to the same function:

@app.route('/name/<first>')@app.route('/name/<first>/<last>')def greet_name(first, last=None):

name = first + ' ' + last if last else first

return "Hello %s!" % name

Page 27: CIS 192: Lecture 10 Web Development with Flask

Templating

What about some real HTML?Flask uses a templating system called Jinja.

<!doctype html>

<title>Hello from Flask</title>

{% if name %}

<h1>Hello {{ name }}!</h1>

{% else %}

<h1>Hello World!</h1>

{% endif %}

Need to put this in a templates folder.

Page 28: CIS 192: Lecture 10 Web Development with Flask

Templating

from flask import render_template

@app.route('/template/')@app.route('/template/<name>')def template(name=None):

return render_template('index.html', name=name)

Page 29: CIS 192: Lecture 10 Web Development with Flask

Templating

Even cooler ...

<!doctype html>

<title>Making a List</title>

<ul>

{% for item in l %}

<li>{{ item }}</li>

{% endfor %}

</ul>

@app.route('/templatelist')def template_list():

l = ['a', 1, True]

return render_template('list.html', l=l)

Page 30: CIS 192: Lecture 10 Web Development with Flask

GET Requests

I Recall: a url can be accessed with parameters, e.g.:/hello?key=value

I Retrieve these parameters from the request.args dictionary

from flask import request

@app.route('/args')def args():

html = ''for key, value in request.args.items():

html += '%s=%s' % (key, value)

html += '<br/>'return html

Page 31: CIS 192: Lecture 10 Web Development with Flask

GET Requests

Even better, using templates:

<!doctype html>

<title>Displaying Params</title>

<ul>

{% for key, value in params.items() %}

<li>{{ key }}={{ value }}</li>

{% endfor %}

</ul>

@app.route('/template_args')def template_args():

return render_template('params.html',params=request.args)

Page 32: CIS 192: Lecture 10 Web Development with Flask

POST Requests

I We can also make POST requests to a url

I Add keyword argument methods=['POST', 'GET'] to theapp.route() decorator

I Check if a request was a POST by looking atrequest.method

I The data from a POST request can be retrieved from therequest.form dictionary

Page 33: CIS 192: Lecture 10 Web Development with Flask

POST Requests

@app.route('/post', methods=['POST', 'GET'])def post():

if request.method == 'POST':return request.form.get('data', 'default')

else:

return 'That was a GET request.'

>>> url = 'http://127.0.0.1:5000/post'>>> req = requests.post(url, data={'data':'test'})>>> req.text

u'test'>>> req = requests.post(url)

>>> req.text

u'default'

Page 34: CIS 192: Lecture 10 Web Development with Flask

POST Requests

What if we try sending a list?

>>> url = 'http://127.0.0.1:5000/post'>>> req = requests.post(url,

data={'data': [1, 2, 3]})

>>> req.text

u'1'

Page 35: CIS 192: Lecture 10 Web Development with Flask

POST Requests

Instead, use JSON! Only ever send strings across the wires.

@app.route('/postlist', methods=['POST'])def post_list():

l = request.form.get('data')l = json.loads(l)

return ','.join(map(str, l))

>>> url = 'http://127.0.0.1:5000/postlist'>>> resp = requests.post(url,

data={'data': json.dumps([1,2,3])})

>>> resp.text

1,2,3

Page 36: CIS 192: Lecture 10 Web Development with Flask

Returning JSON

Instead of returning HTML, what if we want to return JSON?

from flask import jsonify

@app.route('/json')def return_json():

return jsonify({'some': 'data'})

>>> url = 'http://127.0.0.1:5000/json'>>> req = requests.get(url)

>>> req.json()

{u'some': u'data'}

Page 37: CIS 192: Lecture 10 Web Development with Flask

Final Project

Instructions here.