Flask-Themes makes it easy for your application to support a wide range of appearances.
A theme is simply a folder containing static media (like CSS files, images, and JavaScript) and Jinja2 templates, with some metadata. A theme folder should look something like this:
my_theme/
info.json
license.txt
templates/
layout.html
index.html
static/
style.css
The info.json file contains the theme’s metadata, so that the application can provide a nice switching interface if necessary. license.txt is optional and contains the full text of the theme’s license. static is served directly to clients, and templates contains the Jinja2 template files.
Note that exactly what templates you need to create will vary between applications. Check the application’s docs (or source code) to see what you need.
Flask uses the Jinja2 template engine, so you should read its documentation to learn about the actual syntax of the templates.
All templates loaded from a theme will have a global function named theme available to look up the theme’s templates. For example, if you want to extend, import, or include another template from your theme, you can use theme(template_name), like this:
{% extends theme('layout.html') %}
{% from theme('_helpers.html') import form_field %}
If the template you requested doesn’t exist within the theme, it will fall back to using the application’s template. If you pass false as the second parameter, it will only return the theme’s template.
{% include theme('header.html', false) %}
You can still import/include templates from the application, though. Just use the tag without calling theme.
{% from '_helpers.html' import link_to %}
{% include '_jquery.html' %}
You can also get the URL for the theme’s media files with the theme_static function:
<link rel=stylesheet href="{{ theme_static('style.css') }}">
To set up your application to use themes, you need to use the setup_themes function. It doesn’t rely on your application already being configured, so you can call it whenever is convenient. It does three things:
setup_themes takes a few arguments, but the one you will probably be using most is loaders, which is a list of theme loaders to use (in order) to find themes. The default theme loaders are:
It’s easy to write your own loaders, though - a loader is just a callable that takes an application instance and returns an iterable of Theme instances. You can use the load_themes_from helper function to yield all the valid themes contained within a folder. For example, if your app uses an “instance folder” like Zine that can have a “themes” directory:
def instance_loader(app):
themes_dir = os.path.join(app.instance_root, 'themes')
if os.path.isdir(themes_dir):
return load_themes_from(themes_dir)
else:
return ()
Once you have the themes set up, you can call in to the theme machinery with render_theme_template. It works like render_template, but takes a theme parameter before the template name. Also, static_file_url will generate a URL to the given static file.
When you call render_theme_template, it sets the “active template” to the given theme, even if you have to fall back to rendering the application’s template. That way, if you have a template like by_year.html that isn’t defined by the current theme, you can still
templates defined by the theme. This way, the theme author doesn’t have to implement every possible template - they can define templates like the layout, and showing posts, and things like that, and the application-provided templates can use those building blocks to form the more complicated pages.
How exactly you select the theme will vary between applications, so Flask-Themes doesn’t make the decision for you. If your app is any larger than a few views, though, you will probably want to provide a helper function that selects the theme based on whatever (settings, logged-in user, page) and renders the template. For example:
def get_current_theme():
if g.user is not None:
ident = g.user.theme
else:
ident = current_app.config.get('DEFAULT_THEME', 'plain')
return get_theme(ident)
def render(template, **context):
return render_theme_template(get_current_theme(), template, **context)
Warning
Make sure that you only get Theme instances from the theme manager. If you need to create a Theme instance manually outside of a theme loader, that’s a sign that you’re doing it wrong. Instead, write a loader that can load that theme and pass it to setup_themes, because if the theme is not loaded by the manager, then its templates and static files won’t be available, which will usually lead to your application breaking.
This API documentation is automatically generated from the source code.
This contains a theme’s metadata.
Parameters: |
|
---|
The application identifier given in the theme’s info.json. Your application will probably want to validate it.
The author’s name, as given in info.json. This may or may not include their email, so it’s best just to display it as-is.
The human readable description. This is the default (English) version.
The theme’s doctype. This can be html4, html5, or xhtml with html5 being the default if not specified.
The theme’s identifier. This is an actual Python identifier, and in most situations should match the name of the directory the theme is in.
This is a Jinja2 template loader that loads templates from the theme’s templates directory.
A short phrase describing the license, like “GPL”, “BSD”, “Public Domain”, or “Creative Commons BY-SA 3.0”.
The contents of the theme’s license.txt file, if it exists. This is used to display the full license text if necessary. (It is None if there was not a license.txt.)
A URL pointing to the license text online.
This is a dictionary of localized versions of the description. The language codes are all lowercase, and the en key is preloaded with the base description.
The theme’s name, as given in info.json. This is the human readable name.
Any additional options. These are entirely application-specific, and may determine other aspects of the application’s behavior.
The theme’s root path. All the files in the theme are under this path.
The theme’s preview image, within the static folder.
The absolute path to the theme’s static files directory.
The absolute path to the theme’s templates directory.
The URL to the theme’s or author’s Web site.
This sets up the theme infrastructure by adding a ThemeManager to the given app and registering the module containing the views and templates needed.
Parameters: |
|
---|
This renders a template from the given theme. For example:
return render_theme_template(g.user.theme, 'index.html', posts=posts)
If _fallback is True and the themplate does not exist within the theme, it will fall back on trying to render the template using the application’s normal templates. (The “active theme” will still be set, though, so you can try to extend or include other templates from the theme.)
Parameters: |
|
---|
This is a shortcut for getting the URL of a static file in a theme.
Parameters: |
---|
This gets the theme with the given identifier from the current app’s theme manager.
Parameters: |
|
---|
This returns a list of all the themes in the current app’s theme manager, sorted by identifier.
This is responsible for loading and storing all the themes for an application. Calling refresh will cause it to invoke all of the theme loaders.
A theme loader is simply a callable that takes an app and returns an iterable of Theme instances. You can implement your own loaders if your app has another way to load themes.
Parameters: |
|
---|
If an app wasn’t bound when the manager was created, this will bind it. The app must be bound for the loaders to work.
Parameters: |
|
---|
This is a list of the loaders that will be used to load the themes.
This loads all of the themes into the themes dictionary. The loaders are invoked in the order they are given, so later themes will override earlier ones. Any invalid themes found (for example, if the application identifier is incorrect) will be skipped.
This is a dictionary of all the themes that have been loaded. The keys are the identifiers and the values are Theme objects.
This checks whether the application identifier given will work with this application. The default implementation checks whether the given identifier matches the one given at initialization.
Parameters: |
|
---|
This theme will find themes that are shipped with the application. It will look in the application’s root path for a themes directory - for example, the someapp package can ship themes in the directory someapp/themes/.
This checks the app’s THEME_PATHS configuration variable to find directories that contain themes. The theme’s identifier must match the name of its directory.
This is used by the default loaders. You give it a path, and it will find valid themes and yield them one by one.
Parameters: |
|
---|