Categories
Flask

Python Web Development with Flask — Favicon, Background Tasks, and HTTP Method Overrides

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.

Favicon

We can add a favicon by putting it in the static folder and then referencing it.

For example, we can write:

app.py

from flask import send_from_directory, Flask, render_template
import os

app = Flask(__name__)

@app.route('/favicon.ico')
def favicon():
    return send_from_directory(os.path.join(app.root_path, 'static'),
                               'favicon.ico', mimetype='image/vnd.microsoft.icon')

@app.route('/')
def hello_world():
    return render_template('index.html')

templates/index.html

<link rel="shortcut icon"
    href="{{ url_for('static', filename='favicon.ico') }}">
<p>hello world</p>

Then we put our favicon.ico file into the static folder.

Now we should see the favicon displayed in our browser’s tab.

Deferred Request Callbacks

We can add callbacks that are called before or after the current request.

For example, we can write:

from flask import Flask

app = Flask(__name__)

@app.before_request
def before_request():
    print('before called')

@app.after_request
def after_request(response):
    print('after called')
    return response

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

We call the @app.before_request to add a callback that’s run before a request is made.

The @app.after_request decorator lets us add a callback that’s run after a request is made.

The response parameter has the response that we return.

HTTP Method Overrides

We can add HTTP method overrides with our own class.

For example, we can write:

from flask import Flask

class HTTPMethodOverrideMiddleware(object):
    allowed_methods = frozenset([
        'GET',
        'HEAD',
        'POST',
        'DELETE',
        'PUT',
        'PATCH',
        'OPTIONS'
    ])
    bodyless_methods = frozenset(['GET', 'HEAD', 'OPTIONS', 'DELETE'])

    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        method = environ.get('HTTP_X_HTTP_METHOD_OVERRIDE', '').upper()
        if method in self.allowed_methods:
            environ['REQUEST_METHOD'] = method
        if method in self.bodyless_methods:
            environ['CONTENT_LENGTH'] = '0'
        return self.app(environ, start_response)

app = Flask(__name__)
app.wsgi_app = HTTPMethodOverrideMiddleware(app.wsgi_app)

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

to add the HTTPMethodOverrideMiddleware class.

It has the allowed_methods variable to let us set the kinds of HTTP requests that can be made.

bodyless_methods has the types of HTTP requests that doesn’t require a request body.

The __call__ method lets us set the REQUEST_METHOD and the CONTENT_LENGTH request headers and return the request with the changes.

Then we add the override with:

app.wsgi_app = HTTPMethodOverrideMiddleware(app.wsgi_app)

Celery Background Tasks

We can add background tasks in our app with Celery.

To use it, we run:

pip install celery redis

Then we can use it by writing:

from flask import Flask
from celery import Celery

def make_celery(app):
    celery = Celery(
        app.import_name,
        backend=app.config['CELERY_RESULT_BACKEND'],
        broker=app.config['CELERY_BROKER_URL']
    )

    class ContextTask(celery.Task):
        def __call__(self, *args, **kwargs):
            with app.app_context():
                return self.run(*args, **kwargs)

    celery.Task = ContextTask
    return celery

app = Flask(__name__)
app.config.update(
    CELERY_BROKER_URL='redis://localhost:6379',
    CELERY_RESULT_BACKEND='redis://localhost:6379'
)
celery = make_celery(app)

@celery.task()
def add_together(a, b):
    return a + b

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

We have the make_celery function that creates the Celery instance to let us connect to Redis.

Then we set the config with app.config.update .

And then we call make_celery to create the Celery object.

Then we can use the celery object to run our worker and create a Celery task with the @celery.task decorator.

Once we did that and started Redis, we can run:

result = add_together.delay(23, 42)
print(result.wait())

to run the task.

Conclusion

We can add favicons, request callbacks, and background tasks with Flask.

Categories
Flask

Python Web Development with Flask — JSON Requests, Error Pages, and MongoDB

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.

Accepting JSON Requests

Flask can accept JSON request bodies out of the box.

For example, we can write:

from flask import Flask, jsonify, render_template, request
app = Flask(__name__)

@app.route('/add_numbers', methods=['POST'])
def add_numbers():
    content = request.json
    a = content['a']
    b = content['b']
    return jsonify(result=a + b)

to get the request JSON body with the request.json property.

Get Query Parameters

To get query parameters in our route function, we can use the request.args.get method:

from flask import Flask, jsonify, render_template, request
app = Flask(__name__)

@app.route('/add_numbers')
def add_numbers():
    a = request.args.get('a', 0, type=int)
    b = request.args.get('b', 0, type=int)
    return jsonify(result=a + b)

We get the value of the a and b URL parameters.

The 2nd argument is the default value of each.

And the type parameter has the data type to return.

So if we go to http://localhost:5000/add_numbers?a=1&b=2, we get:

{
  "result": 3
}

as the response.

Custom Error Pages

We can add custom error pages for various kinds of errors.

Common error codes that we run into include:

  • 404 — not found
  • 403 — accessing a disallowed resource
  • 410 — access a deleted item
  • 500 — internal server error

We can add error handlers for them by using the @app.errorhandler decorator.

For example, we can write:

app.py

from flask import Flask, render_template
app = Flask(__name__)

@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404

templates/404.html

<p>not found</p>

We pass in 404 ito the @app.errorhandler decorator to add a route function for the 404 errors.

We just render the template whenever we encounter a 404 error.

Therefore, we’ll see ‘not found’ when we go to a URL that’s not mapped to a route handler.

Returning API Errors as JSON

Also, we can return API errors as JSON.

To do that, we use the jsonify function.

For instance, we can write:

from flask import Flask, jsonify, abort
app = Flask(__name__)

@app.errorhandler(404)
def resource_not_found(e):
    return jsonify(error=str(e)), 404

@app.route("/cheese")
def get_one_cheese():
    resource = None

    if resource is None:
        abort(404, description="Resource not found")

    return jsonify(resource)

We have the get_one_cheese function that returns a 404 response if resource is None .

Since it’s none, we see the JSON.

The JSON response is created in the resource_not_found function, which is the handler for 404 errors.

We call jsonify in there with the error in the response.

abort will pass the error into the e parameter of resource_not_found .

So, we get:

{
  "error": "404 Not Found: Resource not found"
}

returned in the response body when we go to http://localhost:5000/cheese.

MongoDB with MongoEngine

We can manipulate MongoDB databases easily with MongoEngine.

To use it, we install:

pip install flask_mongoengine mongoengine

to install the required libraries.

Then we write:

from flask import Flask, jsonify
from flask_mongoengine import MongoEngine
import mongoengine as me

class Movie(me.Document):
    title = me.StringField(required=True)
    year = me.IntField()
    rated = me.StringField()
    director = me.StringField()
    actors = me.ListField()

class Imdb(me.EmbeddedDocument):
    imdb_id = me.StringField()
    rating = me.DecimalField()
    votes = me.IntField()

app = Flask(__name__)
app.config['MONGODB_SETTINGS'] = {
    "db": "myapp",
}
db = MongoEngine(app)

@app.route('/')
def hello_world():
    bttf = Movie(title="Back To The Future", year=1985)
    bttf.actors = [
        "Michael J. Fox",
        "Christopher Lloyd"
    ]
    bttf.imdb = Imdb(imdb_id="tt0088763", rating=8.5)
    bttf.save()
    return 'movie saved'

@app.route('/query')
def query():
    bttf = Movie.objects(title="Back To The Future")
    return jsonify(bttf)

to connect to the MongoDB database and do the database queries in our route.

Before we add our routes, we create the classes for the MongDB document schemas.

The classes are subclasses of the me.Document class.

me.StringField creates a string field.

me.ListField creates a list field.

me.DecimalField creates a floating-point number field.

And me.IntField creates an integer field.

Then we create our Flask app with the Flask clas.

And then we add the database connection settings to the MONGO_SETTINGS config.

Then we invoke the MongoEngine class with the app argument to let our routes connect to the database.

Then in hello_world we create a Movie document and call save to save it.

In the query route, we get the Movie that are saved with the title set to 'Back To The Future' .

Then we can jsonify on the result to return it as the JSON response.

Conclusion

We can accept a JSON body and query parameters in our requests.

Also, we can create custom error pages and use MongoDB databases with Flask.

Categories
Flask

Python Web Development with Flask — Flash Messages

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.

Message Flashing

We can send messages to a template that can be accessed with the next request.

For example, we can write:

app.py

from flask import Flask, render_template, redirect, url_for, flash, request
app = Flask(__name__)
app.secret_key = b'secret'

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    error = None
    if request.method == 'POST':
        flash('You were successfully logged in')
        return redirect(url_for('index'))
    return render_template('login.html', error=error)

templates/login.html

{% block body %}
  <h1>Login</h1>
  {% if error %}
    <p class=error><strong>Error:</strong> {{ error }}
  {% endif %}
  <form method=post>
    <dl>
      <dt>Username:
      <dd><input type=text name=username value="{{
          request.form.username }}">
      <dt>Password:
      <dd><input type=password name=password>
    </dl>
    <p><input type=submit value=Login>
  </form>
{% endblock %}

templates/layout.html

<!doctype html>
<title>My Application</title>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
  {% for message in messages %}
  <li>{{ message }}</li>
  {% endfor %}
</ul>
{% endif %}
{% endwith %}
{% block body %}{% endblock %}

templates/index.html

{% extends "layout.html" %}
{% block body %}
  <h1>Overview</h1>
  <p>Do you want to <a href="{{ url_for('login') }}">log in?</a>
{% endblock %}

We create the flash message with the flash function in app.py .

Then when login is successful, we should the message in the template with the get_flashed_messages function.

Flashing With Categories

We can call flash with a second argument.

The 2nd argument is the category name.

To add the category and render it, we can write:

app.py

from flask import Flask, render_template, redirect, url_for, flash, request
app = Flask(__name__)
app.secret_key = b'secret'

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    error = None
    if request.method == 'POST':
        flash('You were successfully logged in', 'info')
        return redirect(url_for('index'))
    return render_template('login.html', error=error)

templates/login.html

{% block body %}
  <h1>Login</h1>
  {% if error %}
    <p class=error><strong>Error:</strong> {{ error }}
  {% endif %}
  <form method=post>
    <dl>
      <dt>Username:
      <dd><input type=text name=username value="{{
          request.form.username }}">
      <dt>Password:
      <dd><input type=password name=password>
    </dl>
    <p><input type=submit value=Login>
  </form>
{% endblock %}

templates/layout.html

<!doctype html>
<title>My Application</title>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<ul class=flashes>
  {% for category, message in messages %}
  <li class="{{ category }}">{{ message }}</li>
  {% endfor %}
</ul>
{% endif %}
{% endwith %}
{% block body %}{% endblock %}

templates/index.html

{% extends "layout.html" %}
{% block body %}
  <h1>Overview</h1>
  <p>Do you want to <a href="{{ url_for('login') }}">log in?</a>
{% endblock %}

In app.py , we have:

flash('You were successfully logged in', 'info')

to add the 'info' category.

The in layout.html . we call get_flashed_messages with the with_categories parameter set to true to render the category.

Then in the for loop, we get both the category and message and render them.

Filtering Flash Messages

We can also filter flash messages in the template.

For example in templates/layout.html , we write:

<!doctype html>
<title>My Application</title>
{% with messages = get_flashed_messages(category_filter=["info"]) %}
{% if messages %}
<ul class=flashes>
  {% for message in messages %}
  <li>{{ message }}</li>
  {% endfor %}
</ul>
{% endif %}
{% endwith %}
{% block body %}{% endblock %}

to add the category_filter argument to only display flash messages with category 'info' .

Conclusion

We can add flash messages that are displayed in the next request into our templates.

Categories
Flask

Python Web Development with Flask — Form Validation and Template Inheritance

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.

Form Validation with WTForms

We can add form validation into our Flask app with the WTForms library.

To install the library, we run:

pip install wtforms

Then we can use it by writing:

from flask import Flask, request
from wtforms import Form, BooleanField, StringField, PasswordField, validators
app = Flask(__name__)

class RegistrationForm(Form):
    username = StringField('Username', [validators.Length(min=4, max=25)])
    email = StringField('Email Address', [validators.Length(min=6, max=35)])
    password = PasswordField('New Password', [
        validators.DataRequired(),
        validators.EqualTo('confirm', message='Passwords must match')
    ])
    confirm = PasswordField('Repeat Password')
    accept_tos = BooleanField('I accept the TOS', [validators.DataRequired()])

@app.route('/register', methods=['POST'])
def register():
    form = RegistrationForm(request.form)
    if request.method == 'POST':
        if form.validate():
            return 'thanks for registering'
        else:
            return 'registration failed'



We create the RegistrationForm class that extends the Form class from wtforms .

We add the fields in there with the built in constructors.

StringField creates a string field.

The first argument is the name.

The 2nd argument has the validation rules.

validators.length checks the length.

PasswordField creates a password field.

BooleanField creates a boolean field.

validators.DataRequired() lets us make a field required.

We can show fields and registration messages in our template by using a macro.

For example, we can write:

app.py

from flask import Flask, request, render_template
from wtforms import Form, BooleanField, StringField, PasswordField, validators
app = Flask(__name__)

class RegistrationForm(Form):
    username = StringField('Username', [validators.Length(min=4, max=25)])
    email = StringField('Email Address', [validators.Length(min=6, max=35)])
    password = PasswordField('New Password', [
        validators.DataRequired(),
        validators.EqualTo('confirm', message='Passwords must match')
    ])
    confirm = PasswordField('Repeat Password')
    accept_tos = BooleanField('I accept the TOS', [validators.DataRequired()])

@app.route('/register', methods=['GET','POST'])
def register():
    form = RegistrationForm(request.form)
    if request.method == 'POST' and form.validate():
        return 'thanks for registering'
    return render_template('register.html', form=form)

templates/_formhelpers.html

{% macro render_field(field) %}
  <dt>{{ field.label }}
  <dd>{{ field(**kwargs)|safe }}
  {% if field.errors %}
    <ul class=errors>
    {% for error in field.errors %}
      <li>{{ error }}</li>
    {% endfor %}
    </ul>
  {% endif %}
  </dd>
{% endmacro %}

templates/register.html

{% from "_formhelpers.html" import render_field %}
<form method=post>
  <dl>
    {{ render_field(form.username) }}
    {{ render_field(form.email) }}
    {{ render_field(form.password) }}
    {{ render_field(form.confirm) }}
    {{ render_field(form.accept_tos) }}
  </dl>
  <p><input type=submit value=Register>
</form>

We create the render_field macro that we use with the register.html template.

The field function renders the field.

field.errors renders the errors.

In the register.html file, we call render_field to render the fields with the errors with the render_field macro.

Template Inheritance

We can inherit from a base template so we can have shared items in there.

For example, we can write:

app.py

from flask import Flask, render_template
app = Flask(__name__)

@app.route('/')
def register():
    return render_template('index.html')

templates/layout.html

<!doctype html>
<html>
  <head>
    {% block head %}
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
    <title>{% block title %}{% endblock %} - My Webpage</title>
    {% endblock %}
  </head>
  <body>
    <div id="content">{% block content %}{% endblock %}</div>
    <div id="footer">
      {% block footer %}
      &copy; Copyright 2010 by <a href="http://domain.invalid/">you</a>.
      {% endblock %}
    </div>
  </body>
</html>

templates/index.html

{% extends "layout.html" %}
{% block title %}Index{% endblock %}
{% block head %}
  {{ super() }}
  <style type="text/css">
    .important { color: #336699; }
  </style>
{% endblock %}
{% block content %}
  <h1>Index</h1>
  <p class="important">
    Welcome on my awesome homepage.
{% endblock %}

static/style.css

body {
    font-size: 20px;
}

In layout.html , we add the blocks with the block keyword.

Then we override them with our own content with the index.html template.

Conclusion

We can add form validation and base templates with Flask.

Categories
Flask

Python Web Development with Flask — SQLAlchemy ORM

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.

Using Flask with SQLAlchemy

We can use Flask with the SQLAlchemy ORM.

First, we install the sqlalchemy package by running:

pip install sqlalchemy

Next, we create the database file with the SQLite browser app.

We create a people table with the id integer primary key column and the name text column.

Then we have the file as database.db in the root of the Flask project folder.

Then, we can write to use it:

from flask import Flask, g
from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.orm import mapper

engine = create_engine('sqlite:///database.db', convert_unicode=True)
metadata = MetaData(bind=engine)
db_session = scoped_session(sessionmaker(autocommit=False,
                                         autoflush=False,
                                         bind=engine))

metadata.create_all(bind=engine)
app = Flask(__name__)

@app.teardown_appcontext
def shutdown_session(exception=None):
    db_session.remove()

class Person(object):
    query = db_session.query_property()

    def __init__(self, name=None, id=None):
        self.name = name
        self.id = id

    def __repr__(self):
        return '<Person %r>' % (self.name)

people = Table('people', metadata,
              Column('id', Integer, primary_key=True),
              Column('name', String(50), unique=True),
              )
mapper(Person, people)

@app.route('/')
def index():
    person = people.select(people.c.id == 1).execute().first()
    return person.name

We connect to the database with the create_engine call.

Then we create the Metadata object so tjhat we can create models that uses the database connection.

Then we call scoped_session to create the database session.

autocommit set to false disables auto commit.

autoflush sets to false disabled auto flush.

bind set to engine binds the database session to our connection.

Then we call metadata.create_all to bind the engine to our app so we can create Table objects that uses the connection for queries.

Then we have the shutdown_sesion function that calls db_session.remove to disconnect the database when the app stops running.

Next, we create the Person class to add the query into our app.

This lets us use the class to query the database.

The __init__ method sets the instance properties with the names from the database columns.

__repr__ returns the string representation of the entry.

Then we use the Table construictor to create the people table object with the id and name columns.

They should match what we have in the database.

Then we call mapper to map the Person class to the people table.

Finally, in the index route function, we make a query in the table and then return the first result with first .

Then we return the value of the name column of the result.

To insert data, we change index to:

@app.route('/')
def index():
    con = engine.connect()
    con.execute(people.insert(), name='bob')
    person = people.select(people.c.id == 1).execute().first()
    return person.name

Everything above this function is the same as what we have before.

We connect to the database with engine.connect() .

Then we call con.execute to run the connect, people.insert() indicates we’re inserting an entry.

name indicates that we’re inserting to the name column.

Conclusion

We can use the SQLAlchemy ORM with Flask easily.