Categories
Flask

Python Web Development with Flask — URL Processors and SQLite

Flask is a simple web framework written in Python.

In this article, we’ll look at how to develop simple Python web apps with Flask.

URL Processors

We can add a URL processor to let us share resources with similar URLs.

With it, we don’t have to specify different routes that map to similar URLs.

For example, we can write:

from flask import Flask, g, request

app = Flask(__name__)

@app.url_defaults
def add_language_code(endpoint, values):
    if 'lang_code' in values or not g.lang_code:
        return
    if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
        values['lang_code'] = g.lang_code

@app.url_value_preprocessor
def pull_lang_code(endpoint, values):
    g.lang_code = values.pop('lang_code', None)

@app.route('/<lang_code>/')
def index():
    return 'index %s' % g.lang_code

@app.route('/<lang_code>/about')
def about():
    return 'about %s' % g.lang_code

to add a URL preprocessor, which is run before the route functions are run.

The add_language_code function is run to set the lang_code from the g.lang_code property if it exists.

The app.url_map.is_endpoint_expecting method is used to check if the lang_code URL parameter is expected.

The URL preprocessor function is the pull_lang_code function.

We use the @app.url_value_preprocessor decorator to register the URL preprocessor function.

values has the URL parameters.

Then we call values.pop to get the value of the 'lang_code' URL parameter and set that as the value of g.lang_code .

Then in our route functions, we can omit the lang_code parameter.

We get the value for lang_code from the g.lang_code property instead.

So when we go to http://127.0.0.1:5000/en/about, we see ‘about en’.

And when we go to http://127.0.0.1:5000/en/, we see ‘index en’.

Internationalized Blueprint URLs

We can add URL preprocessors for blueprints.

For example, we can write:

from flask import Flask, g, request, Blueprint

app = Flask(__name__)
bp = Blueprint('frontend', __name__, url_prefix='/<lang_code>')

@bp.url_defaults
def add_language_code(endpoint, values):
    if 'lang_code' in values or not g.lang_code:
        return
    if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
        values['lang_code'] = g.lang_code

@bp.url_value_preprocessor
def pull_lang_code(endpoint, values):
    g.lang_code = values.pop('lang_code', None)

@bp.route('/')
def index():
    return 'index %s' % g.lang_code

@bp.route('/about')
def about():
    return 'about %s' % g.lang_code

app.register_blueprint(bp)

We create the bp blueprint with the Blueprint constructor.

It has the url_prefix parameter to make it accept the lang_code URL parameter as the prefix.

Then we add the same URL preprocessor function as we do before to get the lang_code parameter and set it as the value of the g.lang_code property.

The difference is that we use the @bp.url_value_preprocessor decorator to register the URL preprocessor.

The @bp.url_defaults decorator is used to setting the default value of the lang_code URL parameter.

Then the bp blueprint routes can be used the same way as we do before.

After defining the routes, we call app.register_blueprint to register the bp blueprint.

SQLite 3 with Flask

We can use SQLite 3 with Flask.

To do this, we can write:

from flask import Flask, g
import sqlite3

app = Flask(__name__)
DATABASE = './database.db'

def get_db():
    db = getattr(g, '_database', None)
    if db is None:
        db = g._database = sqlite3.connect(DATABASE)
    return db

@app.teardown_appcontext
def close_connection(exception):
    db = getattr(g, '_database', None)
    if db is not None:
        db.close()

def query_db(query, args=(), one=False):
    cur = get_db().execute(query, args)
    rv = cur.fetchall()
    cur.close()
    return (rv[0] if rv else None) if one else rv

@app.route('/')
def index():
    names = []
    for person in query_db('select * from people'):
        names.append(person[0])
    return ','.join(names)

We create the get_db function to connect to the database.

close_connection closes the connection.

It’s run when we stop the app as indicated by the @app.teardown_context decorator.

The query_db function queries the data with the get_db function to make the connection.

Then we fetch all the items returned by the query .

It returns the result, and we use that in our index route function.

We created a people table with the name text column.

So person[0] returns the value of the name column.

Conclusion

We can add URL processors to make managing similar URLs easier.

Also, we can use SQLite with our app.

Categories
Flask

Python Web Development with Flask — Commands and Blueprints, Factories, and Exceptions

Flask is a simple web framework written in Python.

In this article, we’ll look at how to develop simple Python web apps with Flask.

Registering Commands with Blueprints

We can register commands with Blueprints.

For example, we can write:

from flask import Flask
import click
from flask import Blueprint
app = Flask(__name__)
bp = Blueprint('students', __name__)

@bp.cli.command('create')
@click.argument('name')
def create(name):
    print('create %s' % name)

app.register_blueprint(bp)

@app.route('/')
def hello_world():
    return 'hello world'

We create our blueprint with the Blueprint class.

Then we call @bp.cli.command decorator to create the 'create' command in the blueprint.

We specify the command line argument with the @click.argument decorator.

Then we call app.register_blueprint to register the blueprint.

Then when we run:

flask students create alice

We see ‘created alice’ displayed.

Application Context

We can use the @with_appcontext decorator to run the command function with the app context pushed.

This way, we have access to the app and its config in the command function.

For example, we can write:

from flask import Flask
import click
from flask.cli import with_appcontext
app = Flask(__name__)

@click.command('do_work')
@with_appcontext
def do_work():
    print(app)

app.cli.add_command(do_work)

@app.route('/')
def hello_world():
    return 'hello world'

to add the do_work task into our app.

When we run:

flask do_work

we see the app:

<Flask 'app'>

logged.

Application Factories

We can create a factory function for our app so that we can create multiple instances of our app.

This makes testing easier.

For example, we can write:

from flask import Flask

def create_app(config_filename):
    app = Flask(__name__)
    app.config.from_object(config_filename)
    print(app.config)

    @app.route('/')
        def hello_world():
            return 'hello world'
    return app

create_app('config')

to create a create_app function that takes the config_filename parameter.

Then we can read the config parameter we want according to the value of config_filename .

API Exceptions

We can create our own exception classes and use them in our Flask app.

For example, we can write:

from flask import Flask, jsonify

class InvalidUsage(Exception):
    status_code = 400

    def __init__(self, message, status_code=None, payload=None):
        Exception.__init__(self)
        self.message = message
        if status_code is not None:
            self.status_code = status_code
        self.payload = payload

    def to_dict(self):
        rv = dict(self.payload or ())
        rv['message'] = self.message
        return rv

app = Flask(__name__)

@app.errorhandler(InvalidUsage)
def handle_invalid_usage(error):
    response = jsonify(error.to_dict())
    response.status_code = error.status_code
    return response

@app.route('/')
def hello_world():
    raise InvalidUsage('This view is gone', status_code=410)

We create the InvalidUsage class which extends the Exception class.

The __init__ method initializes the mesaage and payload values.

to_dict is a method that puts the instance variables into a dictionary and returns it.

Then we register the error handler for this exception with the handle_invalid_usage method.

The @app.errorhandler decorator is used to handle the errors.

In the function, we call error.to_dict() to get the dictionary version of the error and returns it as the JSON response.

Then in the hello_world route function, we raise the InvalidUsage exception.

And when we go to http://127.0.0.1:5000/, we see:

{
  "message": "This view is gone"
}

in the response.

Conclusion

We can register commands with blueprints, create app factory functions, and add our own API exceptions with Flask.

Categories
Flask

Python Web Development with Flask — Blueprints and Commands

Flask is a simple web framework written in Python.

In this article, we’ll look at how to develop simple Python web apps with Flask.

Blueprints

We can use Blueprints to modularize our apps with Flask.

For example, we can write:

app.py

from flask import Flask, request
from simple_page import simple_page

app = Flask(__name__)
app.register_blueprint(simple_page)

simple_page.py

from flask import Blueprint, render_template, abort
from jinja2 import TemplateNotFound

simple_page = Blueprint('simple_page', __name__,
                        template_folder='templates')

@simple_page.route('/', defaults={'page': 'index'})
@simple_page.route('/<page>')
def show(page):
    try:
        return render_template('pages/%s.html' % page)
    except TemplateNotFound:
        abort(404)

templates/pages/users.html

<p>users</p>

In the simple_pages.py file, we create the blueprint.

We create it with the Blueprint class.

The first argument is the name.

The 3rd argument is the template folder location.

Then to create a route, we call route on the simple_page blueprint.

The defaults parametrer has a dict that has the default value for the page URL parameter.

Then in the function, we call render_template to render the template with the given file name.

In app.py , we call app.register_blueprint to register the blueprint.

When we go to http://127.0.0.1:5000/users, we see ‘users’ displayed.

We can add a URL prefix for the blueprint.

For example, we can write:

app.py

from flask import Flask, request
from simple_page import simple_page

app = Flask(__name__)
app.register_blueprint(simple_page, url_prefix='/pages')

simple_page.py

from flask import Blueprint, render_template, abort
from jinja2 import TemplateNotFound

simple_page = Blueprint('simple_page', __name__,
                        template_folder='templates')

@simple_page.route('/', defaults={'page': 'index'})
@simple_page.route('/<page>')
def show(page):
    print(page)
    try:
        return render_template('pages/%s.html' % page)
    except TemplateNotFound:
        abort(404)

templates/pages/users.html

<p>users</p>

We add the url_prefix parameter into the app.register_blueprint to add the URL prefix.

When we go to http://127.0.0.1:5000/pages/users, we see ‘users’ displayed.

Static Files

We can add a static files folder with Blueprints.

To do that, we pass in the static_folder parameter.

To do that, we write:

app.py

from flask import Flask, request
from simple_page import simple_page

app = Flask(__name__)
app.register_blueprint(simple_page, url_prefix='/pages')

simple_page.py

from flask import Blueprint, render_template, abort
from jinja2 import TemplateNotFound

simple_page = Blueprint('simple_page', __name__,
                        template_folder='templates',
                        static_folder='static')

@simple_page.route('/', defaults={'page': 'index'})
@simple_page.route('/<page>')
def show(page):
    print(page)
    try:
        return render_template('pages/%s.html' % page)
    except TemplateNotFound:
        abort(404)

static/styles.css

body {
    font-weight: bold;
}

templates/pages/users.html

<link rel="stylesheet" href="{{ url_for('simple_page.static', filename='styles.css')
 }}">
<p>users</p>

In simple_page.py , we add the static_folder parameter to set the static folder location.

Then we put the styles.css in the static folder and set the styles we want.

In users.html , we have:

url_for('simple_page.static', filename='styles.css')

to get the path to the styles.css file.

Command Line Interface

We can add commands into our Flask app.

For example, we can write:

from flask import Flask
import click

app = Flask(__name__)

@app.cli.command("create-user")
@click.argument("name")
def create_user(name):
    print('create %s' % name)

@app.route('/')
def hello_world():
    return 'hello world'

We add the create-user command with the @app.cli.command decorator.

The name parameter is obtained from the name command-line argument.

The command-line argument is specified by the @click.argument decorator.

So when we run:

flask create-user admin

in the command line, we see ‘create admin’ displayed.

Also, we can put commands in groups.

For example, we can write:

from flask import Flask
import click
from flask.cli import AppGroup

app = Flask(__name__)
user_cli = AppGroup('user')

@user_cli.command('create')
@click.argument('name')
def create_user(name):
    print('create %s' % name)

app.cli.add_command(user_cli)

@app.route('/')
def hello_world():
    return 'hello world'

to add the 'user' command group.

Then we specify our commands in the group with the @user_cli.command decorator.

And we register the command with the app.cli.add_command method.

Now when we run:

flask user create demo

we see ‘create demo’ displayed.

Conclusion

We can organize our Flask apps with blueprints and add commands to our Flask app.

Categories
Flask

Python Web Development with Flask — Methods Views Decorators and Context

Flask is a simple web framework written in Python.

In this article, we’ll look at how to develop simple Python web apps with Flask.

Decorating Views

We can add decorators to view classes with the decorators property.

For example, we can write:

from flask import Flask, request, session, abort
from flask.views import MethodView

app = Flask(__name__)
app.secret_key = b'secret'

def user_required(f):
    def decorator(*args, **kwargs):
        if 'username' not in session:
            abort(401)
        return f(*args, **kwargs)
    return decorator

class UserAPI(MethodView):
    decorators = [user_required]

    def get(self):
        return 'get'

    def post(self):
        return 'post'

class LoginAPI(MethodView):
    def get(self):
        session['username'] = 'username'
        return 'logged in'

class LogoutAPI(MethodView):
    def get(self):
        session.pop('username', None)
        return 'logged out'

app.add_url_rule('/users/', view_func=UserAPI.as_view('users'))
app.add_url_rule('/login/', view_func=LoginAPI.as_view('login'))
app.add_url_rule('/logout/', view_func=LogoutAPI.as_view('logout'))

We add the LoginAPI and LogoutAPI to and add the get methods to them to add the username session key and remove it respectively.

In UserAPI , we user the user_required decorator to check whether the 'username' key in the session object.

If it’s not, we return 401.

Otherwise, we call the method that we’re requesting in the class.

Method Views for APIs

We can get URL parameters in our route methods.

For example, we can write:

from flask import Flask, request, session, abort
from flask.views import MethodView

app = Flask(__name__)

class UserAPI(MethodView):
    def get(self, user_id):
        print(user_id)
        if user_id is None:
            return 'users'
        else:
            return str(user_id)

    def post(self):
        return 'post'

    def delete(self, user_id):
        return str(user_id)

    def put(self, user_id):
        return 'put'

user_view = UserAPI.as_view('user_api')
app.add_url_rule('/users/', defaults={'user_id': None},
                 view_func=user_view, methods=['GET', ])
app.add_url_rule('/users/', view_func=user_view, methods=['POST', ])
app.add_url_rule('/users/<int:user_id>', view_func=user_view,
                 methods=['GET', 'PUT', 'DELETE'])

We have the UserAPI class that has the get , post , delete and put methods.

The user_id parameter is the URL parameter.

The defaults parameter is set on the GET route to set the user_id with a default value.

We also accept the user_id URL parameter in the PUT and DELETE routes.

Application Context

We can use the application context to keep track of the app0level data during a request, CLI command, or other activity.

We can access the global context with the g variable.

For example, we can write:

from flask import Flask, g
from flask.views import MethodView

app = Flask(__name__)

def connect_to_database():
    pass

def get_db():
    if 'db' not in g:
        g.db = connect_to_database()
    return g.db

@app.teardown_appcontext
def teardown_db(response_or_exc):
    db = g.pop('db', None)
    if db is not None:
        db.close()

@app.route('/')
def hello_world():
    return 'hell world'

We set the g.db property if 'db' isn’t in the g variable.

In the teardown_db function, then we call g.pop method to remove the 'db' property from the object.

Request Context

Flask automatically pushes a request context when handling a request.

For example, if we have:

from flask import Flask, request

app = Flask(__name__)

@app.route('/')
def hello():
    print('during view')
    return 'Hello, World!'

@app.teardown_request
def show_teardown(exception):
    print('after with block')

with app.test_request_context():
    print('during with block')

with app.test_client() as client:
    client.get('/')
    print(request.path)

We get the context with the app.test_request_context() method.

The show_teardown method is run after the with blocks are run.

So we get:

during with block
after with block
during view
/
after with block

logged when we run the app.

Conclusion

We can decorate method views. Also, we can get the app context and use it to request data with Flask.

Categories
Flask

Python Web Development with Flask — Pluggable Views

Flask is a simple web framework written in Python.

In this article, we’ll look at how to develop simple Python web apps with Flask.

Pluggable Views

Flask has pluggable views.

They use classes to render views instead of functions.

For example, we can write:

app.py

from flask import Flask, render_template
from flask.views import View

app = Flask(__name__)

class ShowUsers(View):

    def dispatch_request(self):
        users = [
            {
                'name': 'james'
            },
            {
                'name': 'mary'
            },
        ]
        return render_template('users.html', users=users)

app.add_url_rule('/users/', view_func=ShowUsers.as_view('show_users'))

templates/users.html

{% for u in users %}
<p>{{u.name}}</p>
{% endfor %}

We add the ShowUsers class which inherited from the View class.

It has the dispatch_request method that renders the template with some data.

Then to map the class to a URL, we call the app.add_url_rule method with the URL path and the view_func parameter.

The ShowUsers.as_view method takes the name of the view that we’ll have.

We can make this code more flexible by providing a base class for rendering the template.

Then we create a subclass with the data to render the view.

To do that, we can write:

app.py

from flask import Flask, render_template
from flask.views import View

app = Flask(__name__)

class ListView(View):
    def get_template_name(self):
        raise NotImplementedError()

    def render_template(self, context):
        return render_template(self.get_template_name(), **context)

    def dispatch_request(self):
        context = {'objects': self.get_objects()}
        return self.render_template(context)

class UserView(ListView):
    def get_template_name(self):
        return 'users.html'

    def get_objects(self):
        return [
            {
                'name': 'james'
            },
            {
                'name': 'mary'
            },
        ]

app.add_url_rule('/users/', view_func=UserView.as_view('show_users'))

templates/users.html

{% for u in objects %}
<p>{{u.name}}</p>
{% endfor %}

The ListView component is the base class for the view.

get_template_name is implement in the subclasses of this class.

render_template calls render_template from Flask. with the template name returned from the get_template_name method.

The rest of the arguments are passed in from the context object.

dispatch_request passes in the context into the render_template method.

The UserView class extends the ListView class and returns the template name in the get_template_name method.

And get_objects has the objects array that we render in the template.

Method Hints

We can set the methods that are allowed.

For example, we can write:

from flask import Flask, request
from flask.views import View

app = Flask(__name__)

class MyView(View):
    methods = ['GET', 'POST']

    def dispatch_request(self):
        if request.method == 'POST':
            return 'post'
        return 'get'

app.add_url_rule('/myview', view_func=MyView.as_view('myview'))

to add the MyView class.

It has the methods array that sets the request types that are allowed.

In the dispatch_request method, we check the request method with the request.method property and return the response accordingly.

Then we map the class to a URL with the app;.add_url_rule method.

Method Based Dispatching

We can dispatch methods with methods.

For example, we can write:

from flask import Flask, request
from flask.views import MethodView

app = Flask(__name__)

class UserAPI(MethodView):
    def get(self):
        return 'get'

    def post(self):
        return 'post'

app.add_url_rule('/users/', view_func=UserAPI.as_view('users'))

We have the UserAPI class which extends the MethodView class.

Then we add the get method to accept GET requests and the post method to accept POST requests.

And then we call app.add_url_rule to map that class to a URL.

Now when we make a GET request, we see 'get' and when we make a POST request, we see 'post' .

Conclusion

Pluggable views is a useful way for organizing views with Flask.