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.

Categories
Flask

Python Web Development with Flask — Configuration

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.

Update Configuration

We can set the configuration by setting some properties of the Flask object.

For example, we can write:

from flask import Flask
app = Flask(__name__)
app.testing = True

@app.route('/')
def hello_world():
    return 'Hello, World!'

We set the app.testing property to change the TESTING config.

Also, we can set more than one config settings:

from flask import Flask
app = Flask(__name__)
app.config.update(
    TESTING=True,
    SECRET_KEY=b'secret'
)

@app.route('/')
def hello_world():
    return 'Hello, World!'

The app.config.update method updates multiple configs.

Environment and Debug Features

We can set the FLASK_ENV environment variable to change the environment that the code runs in.

For example, we run:

$ export FLASK_ENV=development
$ flask run

in Linux and:

$ set FLASK_ENV=development
$ flask run

in Windows to run the code in development mode.

Configuring from Files

We can call app.config.from_objecr to load the config from a module.

For example, we can write:

app.py

from flask import Flask
app = Flask(__name__)
app.config.from_object('settings')

@app.route('/')
def hello_world():
    return 'Hello, World!'

settings.py

DEBUG = False
SECRET_KEY = b'_5#y2L"F4Q8znxec]/'

We read the config from settings.py with the app.config.from_object method.

Also, we can use the app.config.from_envvar method to read the settings from the path to the file that we set from the environment variable.

For example, we can write:

app.py

from flask import Flask
app = Flask(__name__)
app.config.from_envvar('APP_SETTINGS')

@app.route('/')
def hello_world():
    print(app.config)
    return 'Hello, World!'

settings.cfg

DEBUG = False
SECRET_KEY = b'_5#y2L"F4Q8znxec]/'

Then in Windows, we run:

> set APP_SETTINGS=./settings.cfg
> python -m flask run

to run the app and read the settings from settings.cfg .

On Linux, we run:

$ export APP_SETTINGS=./settings.cfg
$ python -m flask run

Configuring from Environment Variables

We can read config from environment variables with the os.environ.get method.

For example, we can write:

from flask import Flask
import os

app = Flask(__name__)
SECRET_KEY = os.environ.get("SECRET_KEY")
print(SECRET_KEY)

@app.route('/')
def hello_world():
    return 'Hello, World!'

to read the SECRET_KEY environment variable from the OS’s environment variables.

Then we can set the environment variable and run it by running:

> set SECRET_KEY='5f352379324c22463451387a0aec5d2f'
> python -m flask run

on Windows.

On Linux, we run:

$ set SECRET_KEY='5f352379324c22463451387a0aec5d2f'
$ python -m flask run

Development / Production

We can use class inheritance to create a shared config class between different environments.

Then we can create child config classes for different environments.

For example, we can write:

app.py

from flask import Flask
import os

app = Flask(__name__)
app.config.from_object('settings.ProductionConfig')
print(app.config)

@app.route('/')
def hello_world():
    return 'Hello, World!'

settings.py

class Config(object):
    DEBUG = False
    TESTING = False
    DATABASE_URI = 'sqlite:///:memory:'

class ProductionConfig(Config):
    DATABASE_URI = 'mysql://user@localhost/foo'

class DevelopmentConfig(Config):
    DEBUG = True

class TestingConfig(Config):
    TESTING = True

We call app.config.from_object with the 'settings.ProductionConfig' string to get the settings from the ProductionConfig subclass.

Conclusion

There are several ways to read configs for our app with Flask.

Categories
JavaScript

Electron — Taskbar Widgets

Electron is a framework that lets us create cross-platform desktop apps.

The apps are created by creating web apps that are wrapped with a wrapper.

In this article, we’ll look at the add recent documents menu to an Electron app.

Recent Documents

We can use the app.addRecentDocument method to create a recent documents menu.

For example, we can write:

const { app, BrowserWindow } = require('electron')

function createWindow() {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true
    }
  })
  win.loadFile('index.html')
}

app.whenReady().then(createWindow)
app.addRecentDocument('/Users/USERNAME/Desktop/work.type')

in main.js .

We call the addRecentDocument method to add a recent document.

Then app.clearRecentDocuments() method clears the recent documents list.

On Windows, we’ve to register our app by following these Application Registration instructions to register our app.

This way, the recent document items would appear on the list.

On macOS, when a file is requested from the recent documents menu, the openp-file event of app will be emitted from it.

Progress Bar in Taskbar

We can display the process bar in the taskbar by using the win.setProgressBar method.

For example, in main.js , we can write:

const { app, BrowserWindow } = require('electron')

function createWindow() {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true
    }
  })
  win.loadFile('index.html')
  win.setProgressBar(0.75)
}

app.whenReady().then(createWindow)

We pass an argument between 0 and 1 to the setProgressBar method to display the process on the taskbar.

This feature works on Windows, macOS, and Unity.

macOS Dock

On macOS, we can configure the Dock by call app.dock.setMenu to create a dock menu.

For example, in main.js , we write:

const { app, BrowserWindow, Menu } = require('electron')

function createWindow() {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true
    }
  })
  win.loadFile('index.html')
}

app.whenReady().then(createWindow)
const dockMenu = Menu.buildFromTemplate([
  {
    label: 'New Window',
    click() { console.log('New Window') }
  }, {
    label: 'Settings',
    submenu: [
      { label: 'on' },
      { label: 'off' }
    ]
  },
  { label: 'Something Else' }
])

app.dock.setMenu(dockMenu)

We created the menu with the buildFromTemplate method.

The array has the menu entry to create the items.

Then we pass the menu to the app.dock.setMenu method to set the menu.

Windows Taskbar

We can also customize the Windows taskbar.

We can create a JumpList, add custom thumbnails and toolbars, icon overlays, and flash frames.

For example, in main.js , we can write:

const { app, BrowserWindow, Menu } = require('electron')

function createWindow() {
  // Create the browser window.
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true
    }
  })// and load the index.html of the app.
  win.loadFile('index.html')
}

app.whenReady().then(createWindow)
app.setUserTasks([
  {
    program: process.execPath,
    arguments: '--new-window',
    iconPath: process.execPath,
    iconIndex: 0,
    title: 'New Electron Window',
    description: 'Create a new Electron window'
  }
])

We called app.setUserTasks with an array to add entries into the right-click menu on our app’s taskbar entry.

Thumbnail Toolbars

We can add a thumbnail toolbar by using the win.setThumbarButtons method.

For example, we can write:

const { app, BrowserWindow } = require('electron')
const path = require('path');

function createWindow() {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true
    }
  }) win.loadFile('index.html')
  win.setThumbarButtons([
    {
      tooltip: 'cat 1',
      icon: path.join(__dirname, 'cat.jpg'),
      click() { console.log('cat 1 clicked') }
    }, {
      tooltip: 'cat 2',
      icon: path.join(__dirname, 'cat.jpg'),
      flags: ['enabled', 'dismissonclick'],
      click() { console.log('cat 2 clicked.') }
    }
  ])
}

app.whenReady().then(createWindow)

in main.js to add thumbnails to our thumbnail toolbar.

We can pass in an empty array to empty the thumbnail toolbar.

Conclusion

We can display different things in the taskbar like icons and buttons.