<a href=/flask">Flask allows you to have a very flexible mapping of URL pathes to function calls. Let's see what can you do.
A few notes for placeholders:
- Simple <varname> captures anything except slashes.
- <string:varname> is the default prefix so we don't really need to include it. It captures everything except a slash /
- <int:varname> accepts various unicode digits as well
- <float:varname> accpets a floating point numnber like 123.4, but it does not accept 1. or .1 or a simple integer like 42 without any dot.
- <path:varname> accepts any character, including slashes /.
This a sample Flask file with several possible path mappings.
Including one where we created our own rule to match routes that contain a valid IPv4 address.
from flask import Flask
demoapp = Flask(__name__)
@demoapp.route("/")
def main():
return "Main page"
@demoapp.route("/some/path")
def some_path():
return "A fixed path"
@demoapp.route("/user/<name>")
def user_name(name):
return "The name is {}".format(name)
@demoapp.route("/title/<string:name>")
def title(name):
return "The title is {}".format(name)
@demoapp.route("/id/<int:uid>")
def user_id(uid):
return "The uid is {}".format(uid)
@demoapp.route("/coord-x/<float:x>")
def coord_x(x):
return "The x coordinate is {}".format(x)
@demoapp.route("/place/<path:location>")
def place(location):
return "The location is {}".format(location)
@demoapp.route("/coord/<float:x>/<float:y>")
def coord(x, y):
return "The coordinate is ({}, {})".format(x, y)
@demoapp.route("/street/<name>/zip/<code>")
def machine(name, code):
return "The input is {} and {}".format(name, code)
import converters
demoapp.url_map.converters['ipv4'] = converters.IPv4Converter
@demoapp.route('/ip/<ipv4:address>')
def ip_address(address):
return "The IP is {}".format(address)
examples/flask/routes/converters.py
from werkzeug.routing import BaseConverter, ValidationError
import re
class IPv4Converter(BaseConverter):
def to_python(self, value):
match = re.search(r'(\d+)\.(\d+)\.(\d+)\.(\d+)$', value)
if not match:
raise ValidationError()
for i in [1, 2, 3, 4]:
if not 0 <= int(match.group(i)) <= 255:
raise ValidationError()
return value
You can start the application by running
FLASK_APP=app FLASK_DEBUG=1 flask run
And then you can access it using some of the following URLs:
http://localhost:5000/
http://localhost:5000/some/path
http://localhost:5000/user/foobar
http://localhost:5000/user/ Not Found!
Feel free to try anything you like. Below you'll find the test cases that will help you see which route matches which URLs.
You can use more than one placeholders in a route definition and you can even have fixed elements between the placeholders, though I am not sure when would you want to have that.
Testing the routes
I've also included sample code that will test each one of the given routes.
examples/flask/routes/test_app.py
import app
def test_static_routes():
myapp = app.demoapp.test_client()
rv = myapp.get('/')
assert rv.status == '200 OK'
assert b'Main page' == rv.data
rv = myapp.get('/some/path')
assert rv.status == '200 OK'
assert b'A fixed path' == rv.data
def test_one_name():
myapp = app.demoapp.test_client()
rv = myapp.get('/user/foobar')
assert rv.status == '200 OK'
assert b'The name is foobar' == rv.data
rv = myapp.get('/user/foo-bar .$') # accepts any character
assert rv.status == '200 OK'
assert b'The name is foo-bar .$' == rv.data
rv = myapp.get('/user/foo/bar') # except a slash
assert rv.status == '404 NOT FOUND'
assert b'404 Not Found' in rv.data
print(rv.data)
rv = myapp.get('/user/') # and there must be *something*
assert rv.status == '404 NOT FOUND'
assert b'404 Not Found' in rv.data
print(rv.data)
def test_one_string():
myapp = app.demoapp.test_client()
rv = myapp.get('/title/Hello World!')
assert rv.status == '200 OK'
assert b'The title is Hello World!' == rv.data
def test_one_int():
myapp = app.demoapp.test_client()
rv = myapp.get('/id/42')
assert rv.status == '200 OK'
assert b'The uid is 42' == rv.data
rv = myapp.get('/id/0')
assert rv.status == '200 OK'
assert b'The uid is 0' == rv.data
rv = myapp.get('/id/x42') # only accepts digits
assert rv.status == '404 NOT FOUND'
assert b'404 Not Found' in rv.data
print(rv.data)
rv = myapp.get('/id/-1') # not even something that looks a negative int
assert rv.status == '404 NOT FOUND'
assert b'404 Not Found' in rv.data
rv = myapp.get('/id/1.2') # or a dot
assert rv.status == '404 NOT FOUND'
assert b'404 Not Found' in rv.data
rv = myapp.get('/id/%D9%A4') # ٤ ARABIC-INDIC DIGIT FOUR
assert rv.status == '200 OK'
assert b'The uid is 4' == rv.data
rv = myapp.get('/id/٤') # ٤ ARABIC-INDIC DIGIT FOUR
assert rv.status == '200 OK'
assert b'The uid is 4' == rv.data
rv = myapp.get('/id/߅') # NKO DIGIT FIVE
assert rv.status == '200 OK'
assert b'The uid is 5' == rv.data
def test_float():
myapp = app.demoapp.test_client()
rv = myapp.get('/coord-x/4.2')
assert rv.status == '200 OK'
assert b'The x coordinate is 4.2' == rv.data
rv = myapp.get('/coord-x/42') # does not accept simple digits
assert rv.status == '404 NOT FOUND'
assert b'404 Not Found' in rv.data
rv = myapp.get('/coord-x/1.2.3') # nor more than one dot
assert rv.status == '404 NOT FOUND'
assert b'404 Not Found' in rv.data
rv = myapp.get('/coord-x/.2')
assert rv.status == '404 NOT FOUND'
assert b'404 Not Found' in rv.data
rv = myapp.get('/coord-x/2.')
assert rv.status == '404 NOT FOUND'
assert b'404 Not Found' in rv.data
def test_path():
myapp = app.demoapp.test_client()
rv = myapp.get('/place/a/b/c')
assert rv.status == '200 OK'
assert b'The location is a/b/c' == rv.data
rv = myapp.get('/place/a')
assert rv.status == '200 OK'
assert b'The location is a' == rv.data
rv = myapp.get('/place/foo/bar/')
assert rv.status == '200 OK'
assert b'The location is foo/bar/' == rv.data
def test_multiple():
myapp = app.demoapp.test_client()
rv = myapp.get('/coord/4.2/1.3')
assert rv.status == '200 OK'
assert b'The coordinate is (4.2, 1.3)' == rv.data
def test_strange_multiple():
myapp = app.demoapp.test_client()
rv = myapp.get('/street/foo/zip/42')
assert rv.status == '200 OK'
assert b'The input is foo and 42' == rv.data
def test_ip_address():
myapp = app.demoapp.test_client()
rv = myapp.get('/ip/1.2.3.4')
assert rv.status == '200 OK'
assert b'The IP is 1.2.3.4' == rv.data
rv = myapp.get('/ip/1.2.3')
assert rv.status == '404 NOT FOUND'
assert b'404 Not Found' in rv.data
rv = myapp.get('/ip/1.2.0.256')
assert rv.status == '404 NOT FOUND'
assert b'404 Not Found' in rv.data
As they are writtent these two files need to be in the same directory. You can cd in that directory on your terminal and run:
pytest
If you run it with the -s
flag then you'll also see the output from the print
statements in the test
file.
pytest -s
Comments
can I write on the one of html page which is in templates folder from any function in which is written in main flask file?