Contrib Apps

development area

Various, optional apps for commonly needed features of a web site or web application.

Version: 0.4.0-d

Contributing or contrib apps provide pre-defined functionality. Some of this functionality may be used as is, while other features require integration or customization to be effectively employed.

Accounts

development suite

Version: 0.4.0-d

Various apps for managing user accounts.

Developer Reference: Accounts

Account Admin

development app

Version: 0.3.0-d

The user admin app provides a SuperDjango UI for working with users and groups.

Developer Reference: Account Admin

Provides

  • UI

Abstract

The user admin app provides a SuperDjango UI for working with users and groups.

Install

Add superdjango.contrib.accounts.admin.apps.DefaultConfig`,` to ``INSTALLED_APPS.

Note

The SuperDjango UI system is required and UsersMenu must be registered.

Authentication

alpha app

Version: 0.7.0-a

Basic/standard user authentication via user name and/or email.

Developer Reference: Authentication

Provides

Dependencies

Hooks

  • get_login_redirect_url(request): Return a URL string to override the post-login redirect behavior. The first hook that responds is used.

Abstract

The auth app focuses on user login/logout and provides support for intelligent redirection of the user after a successful login.

Install

Add 'superdjango.contrib.accounts.auth.apps.DefaultConfig', to INSTALLED_APPS.

Usage

Default usage may be invoked by loading the auth URLs:

# main/urls.py
from superdjango.contrib.accounts.views import AccountsViewSet

auth = AccountsViewSet(auth=True)

urlpatterns = [
    ...
    path('accounts/', include(auth.urls),
]

You’ll also need to create an auth.html template for your theme:

{% extends "base.html" %}

{% block navbar %}
    {# no navbar #}
{% endblock %}

{% block breadcrumbs %}
    {# no breadcrumbs #}
{% endblock %}

Avatars

development app

Version: 0.4.0-d

Support for user avatars.

Developer Reference: Avatars

Provides

Abstract

Simply implemented user avatars.

Install

Add superdjango.contrib.accounts.avatars.apps.DefaultConfig, to INSTALLED_APPS.

Usage

TODO: Document avatars usage examples.

User Impersonation

development app

Version: 0.3.1-d

Allow authenticated and authorized users to impersonate another user.

Developer Reference: User Impersonation

Provides

Abstract

The impersonation app allows authorized users to impersonate other users.

Install

  1. Add 'superdjango.contrib.accounts.impersonation.apps.DefaultConfig', to your INSTALLED_APPS.

  2. Add 'superdjango.contrib.accounts.impersonation.middleware.UserImpersonationMiddleware', to your list of MIDDLEWARE.

  3. Add 'superdjango.contrib.accounts.impersonation.context_processors.user_is_allowed_to_impersonate', to your context processors.

  4. Add url(r'^accounts/impersonation/', include("superdjango.contrib.accounts.impersonation.urls")), to your urls.py file. (Or use AccountsViewSet.)

  5. Include accounts/includes/user_impersonation_link.html somewhere in your base template, or recreate the link in the area of your choice.

If you do not wish for staff users to be able to impersonate users, then set SUPERDJANGO_USER_IMPERSONATION_ENABLED_FOR_STAFF to False in settings.py.

You may also specify specific groups that are allowed to impersonate in settings.py:

SUPERDJANGO_USER_IMPERSONATION_ENABLED_FOR_GROUPS = ["Advisers", "Managers", "Trainers"]

To enable database logging, you must provide a model. See ImpersonationHistoryModel as a starting point. Then set SUPERDJANGO_USER_IMPERSONATION_MODEL = "my_app_label.MyImpersonation" in settings.py.

Password Management

development app

Version: 0.5.0-d

Allow users to self-manage passwords.

Developer Reference: Password Management

Provides

Abstract

The passwords app focuses on user password management.

Install

Add 'superdjango.contrib.accounts.passwords.apps.DefaultConfig', to your INSTALLED_APPS.

Usage

Default usage may be invoked by loading the password URLs:

# main/urls.py
from superdjango.contrib.accounts.viewsets import AccountsViewSet

passwords = AccountsViewSet(passwords=True)

urlpatterns = [
    ...
    path('accounts/passwords/', include(passwords.urls),
]

User Profiles

alpha app

Version: 0.7.0-a

Allow users to manage their account profiles.

Developer Reference: User Profiles

Provides

Abstract

The profiles app provides support for user-managed profiles.

Install

  1. Add 'superdjango.contrib.accounts.profiles.apps.DefaultConfig', to your INSTALLED_APPS.

  2. Create your profile model by extending ProfileModel (or ProfileMixin).

  3. Set the SUPERDJANGO_USER_PROFILE_MODEL in settings.py.

Also, include profiles in your URLs.

# main/urls.py
from superdjango.contrib.accounts.viewsets import AccountsViewSet

profiles = AccountsViewSet(profiles=True)

urlpatterns = [
    ...
    path('accounts/profile/', include(profiles.urls),
]

Usage

You may implement a user profile using the provided superdjango.contrib.accounts.profiles.models.ProfileModel as a starting point. Or use the superdjango.contrib.accounts.profiles.models.ProfileMixin to implement a profile from scratch.

Once your model is implemented (and migrations applied), set SUPERDJANGO_USER_PROFILE_MODEL to the dotted path of the model in the form of app_label.ModelName.

Account Utils

development app

Version: 0.5.0-d

Utilities for managing user accounts.

Developer Reference: Account Utils

Provides

  • Utilities

Password Management

development app

Version: 0.5.0-d

Additional views for user account management.

Developer Reference: Password Management

Provides

Embeds

experimental app

Version: 0.4.0-x

An app for embedding media in a page.

Developer Reference: Embeds

Provides

Dependencies

Install

Install OEmbed:

pip install python-oembed;

Add 'superdjango.contrib.embeds.apps.DefaultConfig', to INSTALLED_APPS.

Usage

TODO

Error Capture

experimental app

Version: 0.3.1-x

Error (exception) capture and disposition.

Developer Reference: Error Capture

Provides

Dependencies

  • bitbucket-python (optional) Used by the bitbucket backend to create issues when an exception occurs.

  • PyGithub (optional) Used by the github backend to create issues when an exception occurs.

Abstract

Capturing errors (exceptions) outside of the development environment is an important aspect of product management and user experience. See the Django documentation on error reporting.

Tip

There are many more robust exception handling systems than SuperDjango’s Error Capture app. Sentry for example, is highly recommended (and is itself a Django project). These include a great number of features, but may also require a fee. If you desire a simple, yet effective capture implementation or can’t yet justify the cost of a third-party tool, then the Error Capture app may be an alternative.

Install

General

  1. Add superdjango.contrib.errors.apps.DefaultConfig to INSTALLED_APPS.

2) Add superdjango.contrib.errors.middleware.ErrorCaptureMiddleware at the end of your middleware list in settings.py.

3) To enable error capture in development, set SUPERDJANGO_ERROR_CAPTURE_DEBUG = True. This is useful for testing customer error handlers as well as see a preview of your error templates, but it can be a hindrance to troubleshooting.

4) To control how often an error may repeat, set SUPERDJANGO_ERROR_CAPTURE_REPEAT_SECONDS. The default is 3600, or one (1) hour.

5) Specify one or more error capture handlers using SUPERDJANGO_ERROR_CAPTURE_HANDLERS and provide the required settings for each one. See below.

Tip

The last error handler specified is returned as the result if it is an HttpResponse instance.

Bitbucket Handler

Create a Bitbucket issue based on an exception.

Returns: a dictionary with the issue_url.

  1. Install bitbucket-python: pip install bitbucket-python

  2. superdjango.contrib.errors.apps.DefaultConfig must be included in INSTALLED_APPS.

  3. Identify the repo using the SUPERDJANGO_ERROR_CAPTURE_BITBUCKET_REPO setting.

  4. Identify the owner using the SUPERDJANGO_ERROR_CAPTURE_BITBUCKET_OWNER setting.

  5. Provide a email using the SUPERDJANGO_ERROR_CAPTURE_BITBUCKET_EMAIL setting.

  6. Provide a password using the SUPERDJANGO_ERROR_CAPTURE_BITBUCKET_PASSWORD setting.

  7. Add superdjango.contrib.errors.backends.Bitbucket to SUPERDJANGO_ERROR_CAPTURE_HANDLERS.

CSV Handler

Basic data is written to current.csv in th output path, and tracebacks are written as text files in the tracebacks/ directory of the output path.

Returns: A dictionary with the issue_url if the error views are enabled (below). Otherwise, the dictionary includes the identifier of the error.

Note

Each error is assigned a unique ID which exists in the CSV and is used for the file name of the traceback file.

  1. To log errors to a CSV file, add superdjango.contrib.errors.backends.CSV to SUPERDJANGO_ERROR_CAPTURE_HANDLERS.

  2. You must also set SUPERDJANGO_ERROR_CAPTURE_OUTPUT_PATH to the path were the data is stored. For example: SUPERDJANGO_ERROR_CAPTURE_OUTPUT_PATH = os.path.join(BASE_DIR, "../data", "errors).

  3. Optionally set up views.

To access errors from within the project’s UI, load the views.

# main/urls.py
from superdjango.contrib.errors.views import CSVErrorViewSet

urlpatterns = [
    # ...
    path("errors/", include(CSVErrorViewSet().get_urls())),
]

Email Handler

Send an exception via email.

Returns: None

Important

In addition to the settings below, you must also configure Django to send email.

  1. superdjango.contrib.errors.apps.DefaultConfig must be included in INSTALLED_APPS.

  2. Set the “from address” using SUPERDJANGO_ERROR_CAPTURE_FROM_EMAIL.

  3. Set a list of email addresses to which the info is sent using SUPERDJANGO_ERROR_CAPTURE_EMAILS.

  4. Add superdjango.contrib.errors.backends.Email to SUPERDJANGO_ERROR_CAPTURE_HANDLERS.

GitHub Handler

Create a GitHub issue based on an exception.

Returns: A dictionary with the issue_url.

  1. Install PyGithub: pip install PyGithub

  2. superdjango.contrib.errors.apps.DefaultConfig must be included in INSTALLED_APPS.

  3. Identify the repo using the SUPERDJANGO_ERROR_CAPTURE_GITHUB_REPO setting.

  4. Provide a token using the SUPERDJANGO_ERROR_CAPTURE_GITHUB_TOKEN setting.

  5. Add superdjango.contrib.errors.backends.GitHub to SUPERDJANGO_ERROR_CAPTURE_HANDLERS.

Model Handler

Save an error report to the local database.

Returns: A dictionary with the issue_url if the error views are enabled (below). Otherwise, None.

  1. Create an app and extend superdjango.contrib.errors.models.ErrorModel.

Tip

You can override the log() method to handle any custom fields you define on your extended model.

  1. Add the dotted path to this model to settings using SUPERDJANGO_ERROR_CAPTURE_MODEL_NAME.

  2. Add superdjango.contrib.errors.backends.GitHub to SUPERDJANGO_ERROR_CAPTURE_HANDLERS.

  3. Optionally set up views.

To access errors from within the project’s UI, load the views.

# main/urls.py
from superdjango.contrib.errors.views import ModelErrorViewSet

urlpatterns = [
    # ...
    path("errors/", include(ModelErrorViewSet().get_urls())),
]

Important

You cannot use ModelErrorViewSet and CSVErrorViewSet at the same time because these views utilize the same names. You can use both error handlers at once, but only one may be used for error views.

You may also create a custom UI instead, using SuperDjango UI.

# myapp/ui.py
from .models import Error
from superdjango import ui

class ErrorUI(ui.ModelUI):

    detail_options = ui.DetailOptions(
        "name",
        "added_dt",
        "path",
        "line",
        "traceback",
    )
    list_options = ui.ListOptions(
        "name",
        "added_dt",
        "path",
        "line",
    )

class ErrorMenu(ui.Menu):
    items = [
        ErrorUI,
    ]
    label = "Errors"
    prefix = "errors"

ui.site.register(ErrorMenu)

Usage

Filtering Errors

Internally, the error capture system makes use of Django’s django.views.debug.ExceptionReporter class. This provides support for Django’s built-in error filtering functionality.

Creating Your Own Error Handler

An error handler should extend superdjango.contrib.errors.backends.base.ErrorHandler.

To perform additional work, the handle() method is overridden. See the existing handlers for examples.

Once this is done, the custom handler may be added to the SUPERDJANGO_ERROR_CAPTURE_HANDLERS list in the settings.py file.

Overriding Error Templates

The templates used for creTimeZoneSelectionFormating and displaying errors may be overridden by providing your own templates in an app that is loaded above superdjango.contrib.errors.apps.DefaultConfig.

See superdjango/contrib/errors/templates/errors/ for the templates that are defined for the various handlers.

Known Issues

If you have an app that catches all remaining URLs (as with some CMS apps, including Wagtail), then DoesNotExist errors will be captured for things like the favicon. You can of course simply provide the missing file(s).

You may also add django.middleware.common.BrokenLinkEmailsMiddleware to your middleware and define the links that should be ignored. For example:

# settings.py
import re
IGNORABLE_404_URLS = [
    re.compile(r'\.(php|cgi)$'),
    re.compile(r'^/phpmyadmin/'),
    re.compile(r'^/apple-touch-icon.*\.png$'),
    re.compile(r'^/favicon\.ico$'),
    re.compile(r'^/favicon\.ico/$'),
    re.compile(r'^/robots\.txt$'),
]

History

experimental app

Version: 0.3.0-x

An app for tracking the audit history of records in the database.

Developer Reference: History

Provides

Abstract

The history app is an implementation of superdjango.db.history, providing a concrete history with the option to also record field changes.

Install

Add superdjango.contrib.history.apps.DefaultConfig to INSTALLED_APPS.

Usage

Integrating History With SuperDjango UI

Specify the history call back for your model UI.

from superdjango import ui
from superdjango.contrib.history.models import History
from .models import Project

class ProjectUI(ui.ModelUI):
    model = Project
    history_callback = History.log

    # ...

You’ll also need to add the superdjango.contrib.history.ui.HistoryUI to a menu that is registered in order to access history records. Alternatively, you may specify the history class as part of the model UI.

class ProjectUI(ui.ModelUI):
    model = Project
    history_callback = History.log

    history_options = ui.HistoryOptions(History)

    ...

Integrating History with a Custom View

In this example, we had audit history to an update view:

# myapp/views.py
from superdjango.contrib.history.models import History
from superdjango.db.history.utils import get_field_changes

class UpdateTodo(UpdateView):
    ...

    def form_valid(self, form):
        self.object = form.save()

        field_changes = get_field_changes(form, self.model, record=self.object)

        History.log(self.object, self.request.user, History.UPDATE, fields=field_changes)

        ...

Displaying History in a Template

You may use the record_history template tag to display a record’s history, for example in a detail view.

{% load history_tags %}
...
<div class="content">
    ...
</div>
<div class="sidebar">
    {% record_history object %}
</div>

See History Models for more examples.

Internationalization

planning suite

Version: 0.7.0-p

Tools for assisting with internationalizing a site or application.

Developer Reference: Internationalization

Abstract

Tools and resources for assisting with internationalizing a site or application.

Note

The i18n suite does not provide concrete models.

Form fields are provided as an alternative to model fields. In general, we feel these should be preferred because:

  1. Form fields (and especially choices) may be customized at run time.

  2. Choices may change with some regularity, which may generate unpredictable migrations.

See also https://docs.djangoproject.com/en/stable/topics/i18n/

And https://www.w3.org/International/questions/qa-i18n

Countries

planning library

Version: 0.6.2-p

Choices, form fields, and other resources for managing country data.

Developer Reference: Countries

Provides

  • Choices

  • Data

  • Descriptors

  • Factories

  • Forms : fields

Abstract

Country-related data may be used in a variety of ways, including for addresses and shipping. This package wraps country data in an object-oriented interface, providing resources for working with countries.

The data was originally sourced from various public resources and compiled into a re-usable (and translatable) form.

Note

Is it accurate? To the best of our knowledge, yes, but data may change from time to time, and changes may occur outside of our refresh cycle. You should always double check the data for accuracy and report any issues you may find.

Currencies

planning library

Version: 0.2.3-p

Choices, form fields, and other resources for managing currency data.

Developer Reference: Currencies

Provides

  • Choices

  • Descriptors

  • Forms : fields

Languages

experimental library

Version: 0.6.1-x

Choices, constants, form fields, and other resources for managing language data.

Developer Reference: Languages

Provides

  • Choices

  • Constants

  • Data

  • Descriptors

  • Forms : fields

Abstract

Web sites and Web applications may need to deal with language in a variety of ways:

  • Content negotiation for the Accept Language header.

  • Manual selection of an available language.

  • Translation of site or application content.

Navigating this can be difficult. The generally accepted approach to authoritative language codes is using the IANA Language Subtag Registry page. As this data is provided in record-jar format, SuperDjango sources this as JSON from mattcg’s repo (specifically the registry.json and variant.json files) to generate choices and constants.

Install

No special installation steps are required, but you are referred to the Django docs for setting up language detection:

https://docs.djangoproject.com/en/stable/topics/i18n/translation/#how-django-discovers-language-preference

Time Zones

development library

Version: 0.8.2-d

Choices, constants, form fields, and other resources for managing timezones.

Developer Reference: Time Zones

Provides

Dependencies

  • django-solo (required) Used for the abstract TimeZoneSettingsModel.

  • pytz (required) Required, but installed by default with Django.

Abstract

The timezones app provides resources for specifying and managing timezones.

See https://docs.djangoproject.com/en/3.0/topics/i18n/timezones/

Notifications

experimental app

Version: 0.4.0-x

Facilitates user notifications within a project, optionally sending email and SMS.

Developer Reference: Notifications

Provides

Abstract

The notifications app is primarily meant to provide in-app (e.g. in-project) notifications, but may also be used to send email and SMS when supported.

Install

Add superdjango.contrib.notifications.apps.DefaultConfig to INSTALLED_APPS.

Run ./manage.py migrate.

Sending Email

If you will be sending notifications via email:

  1. Define the email address from which the message is sent using SUPERDJANGO_NOTIFICATIONS_FROM_EMAIL.

  2. Define the from name of the email address using SUPERDJANGO_NOTIFICATIONS_FROM_NAME.

Sending SMS/Text

If you will be sending notifications via SMS, you’ll need to create a callback which integrates with a text messaging service such as Twilio.

The callback must accept a body, mobile number, and optionally a from number. For example:

def send_sms(body, number, from_number=None):
    # ...

Set SUPERDJANGO_NOTIFICATIONS_SMS_CALLBACK to the dotted path of the callback. Optionally set the SUPERDJANGO_NOTIFICATIONS_FROM_NUMBER.

Usage

The notifications system allows developers to queue up notifications for users. It is also possible for administrators or authorized users to create notifications using the provided UI (see below).

Creating a Notification Programmatically

To create a notification for a user:

from django.contrib.auth import get_user_model
from superdjango.contrib.notifications.models import Notification

UserModel = get_user_model()

body = "This is a test notification."
subject = "Testing 123"
users = [
    UserModel.objects.get(pk=1),
    UserModel.objects.get(pk=2),
    UserModel.objects.get(pk=3),
]
notification = Notification.create_for(body, subject, users)

You can of course pass in a list of users with only one user instance.

Sending Notifications

The notifications app makes use of a queue pattern where the actual links to a user (and optional email/SMS) must be executed on a regular schedule. This is the purpose of the send_notifications management command.

Create a shell script which loads the Python environment and executes the command:

#! /usr/bin/env bash

cd /path/to/project;
source python/bin/activate;
cd source;
./manage.py send_notifications;

Then add the script to a cron job:

# send notifications every 15 minutes
*/15 * * * * root /path/to/project/cron/send_notifications.sh

Displaying Notifications

Various template tags are provided for displaying a user’s notifications in your templates. All require the current user as a parameter.

has_notifications: Indicates whether a user has unread notifications.

{% if has_notifications request.user %}
    <div class="alert alter-info">You have some notifications.</div>
{% endif %}

notification_bar: Utilizes the notifications/tags/notification_bar.html template to display a promoted notification at the top of a page.

<head>
    ...
    <link rel="stylesheet" href="{% static "superdjango/contrib/notifications/css/notification-bar.css" %}">
</head>
<body>
    {% notification_bar request.user %}
    ...

    <script src="{% static "superdjango/contrib/notifications/js/notification-bar.js" %}"></script>
</body>

If the AJAX views are set up using the automatic method (below), you may replace notification-bar.js with notification-bar-ajax.js. Otherwise, additional work is required to override notification-bar-ajax.js so that it refers to the correct URL.

unread_notification_count: Returns the number of unread notifications.

<div class="notifications">
    <i class="fas fa-bell"></i> Notifications
    <span class="badge badge-danger">{% unread_notification_count request.user %}</span>
</div>

unread_notifications: Utilizes the notifications/tags/notification_items.html template to display a list of notifications.

<div class="notifications">
    {% unread_notifications request.user %}
</div>

Finally, the included notify_web_api.html template may be used to display in-browser messages for promoted notifications.

<body>
    ...
    {% include "notifications/includes/notify_web_api.html" %}
</body>

Utilizing the Standard Views

Detail and list views are provided for displaying notifications to users.

# main/urls.py
from superdjango.contrib.notifications.views import NotificationsViewSet

urlpatterns = [
    path("notifications/", include(NotificationsViewSet().get_urls())),
]

Utilizing the AJAX Views

The notification apps provides two (2) AJAX views; one for obtaining unread notifications, and the other for marking a notification as read.

To automatically include these views, simply add superdjango.interfaces.ajax.apps.AutoConfig to your INSTALLED_APPS and include the AJAX URLs in your main urls.py file. See AJAX.

You may also manually include the views:

# main/urls.py
from superdjango.contrib.notifications.views import AjaxNotificationsViewSet

urlpatterns = [
    # ...
    path("ajax/notify/", include(AjaxNotificationsViewSet().get_urls())),
    # ...
]

Setting up the UI

The notification apps comes with pre-defined configuration for SuperDjango UI. You may use it as is by registering the NotificationsMenu with the UI, or customize as desired.

# glue/ui.py
from superdjango import ui
from superdjango.contrib.notifications.ui import NotificationsMenu

ui.site.register(NotificationsMenu)

Releases

experimental app

Version: 0.2.0-x

Provides support for managing project releases.

Developer Reference: Releases

Provides

Dependencies

  • markdown (required) Used to generate release pages from Markdown files.

  • semver (required) Used for version bumping.

Abstract

Managing releases in a consistent manner is a strategic strength for any project. Additionally, the ability to maintain release information for both users, developers, and administrators provides essential communication regarding each release of the project and paints a historical picture of the project’s progress.

Installation

Install requirements:

pip install Markdown semver;

Add superdjango.contrib.release.apps.DefaultConfig to INSTALLED_APPS.

Optionally configure the following settings:

# Markdown extensions for rendering article content.
SUPERDJANGO_RELEASE_PATH = "/path/to/releases/"

The default is os.path.join(settings.BASE_DIR, "../deploy", "releases").

Add URLs:

urlpatterns = [
    # ...
    path('releases/', include(superdjango.contrib.support.urls),
    # ...
]

Note

If superdjango.contrib.support is installed, the release app’s views will automatically integrate with the built-in help site. See the documentation for the support app for install.

Usage

To create a new release:

./manage.py create_release -m 2

Customize the INI files and content files as desired.

Scheduler

experimental app

Version: 0.5.0-x

Provides support for scheduling jobs from the command line.

Developer Reference: Scheduler

Provides

Dependencies

  • schedule (required) Used to execute scheduled jobs.

Abstract

Backend (that is, server-side) jobs are a common necessity for many web-based applications. On POSIX systems, the cron job system is sometimes adequate, sometimes not so much.

The scheduler app provides a solution for job scheduling that does not depend on cron while allowing app developers to define callbacks in Python that maybe configured to execute on a pre-determined schedule.

Administrators or authorized users may optionally configure these jobs.

Install

Make sure a config/ directory exists in project root.

If automatic discovery of jobs is desired, add superdjango.contrib.scheduler.apps.AutoConfig to INSTALLED_APPS. Otherwise, create a scheduler.ini file in the config/ directory (see below).

For automated discovery, the Python module name defaults to scheduler, but may changed using the SUPERDJANGO_SCHEDULER_MODULE_NAME setting.

Usage

There are two (2) means of using the scheduler:

  1. Manually configuring jobs by creating an maintaining the scheduler.ini file.

  2. Auto discovery of jobs.

Important

Note that the included (concrete) models are only used when auto-discovery is enabled.

Manually Configuring Jobs

Scheduled jobs are stored in a scheduler.ini file. This is assumed to be located in the config/ directory of project root, but the location may be specified using the SUPERDJANGO_SCHEDULER_PATH setting.

Each section of the INI represents a recurring job. The section name becomes the label of the job. Section parameters establish the attributes of the job to be performed. These are:

  • active: Optional. yes (the default) or no.

  • at: Optional. The time of day to run the job in HH:MM (24 hour) format.

  • call: Required. The callback to use for the job in dotted path format.

  • description: Optional. A description may be provided to further explain or comment on the job.

  • every: Required. Establishes the timing and interval in frequency interval format. For example: every = 10 minutes.

The valid frequencies are:

  • second

  • seconds

  • minute

  • minutes

  • hour

  • hours

  • day

  • days

  • week

  • weeks

  • monday

  • tuesday

  • wednesday

  • thursday

  • friday

  • saturday

  • sunday

Tip

at is only applied when specifying a weekday frequency.

Additional parameters within the section become keyword arguments passed to the callback.

Here are some examples:

[run a test job]
call = example.scheduler.test_job
every = 5 seconds
testing = True

[this job should never make it to the scheduler]
call = example.scheduler.nonexistent_job
description = A nonexistent callback will not make it into the schedule.
every = 5 seconds

[this job is inactive]
active = no
call = example.automation.inactive_job
every = 10 minutes

[this job runs on sunday]
callback = example.scheduler.sunday_cleanup
frequency = sunday
at = 23:30

Automatic Discovery of Jobs

The provided registry interface allows for any app in the project to report that it has one or more jobs that may be included in the scheduler.

  1. To build a list of jobs in the database, run: ./manage.py scheduler_discover_jobs

  2. Activate/deactivate jobs in the UI.

  3. Export the scheduler.ini file: ./manage.py scheduler_export_ini

See Creating Job Callbacks below.

You may provide a user interface for automated discovery by registering the UI menu provided with the scheduler.

# glue/ui.py
from superdjango import ui
from superdjango.contrib.scheduler.ui import ScheduledJobsMenu

ui.site.register(ScheduledJobsMenu)

Listing the Available Jobs

Regardless of manual or automatic discovery, the scheduler_list_jobs command will list the jobs found in the scheduler.ini file.

Setting Up Supervisor D

Some means of executing jobs is required. One way to do this is to set up supervisord.

Tip

You can use the management command: ./manage.py scheduler_export_supervisord to create the configuration on the server.

This requires a supervisord configuration file which points to a shell script.

[program:superdjango_scheduler]
command=/path/to/project/cron/scheduler.sh
autostart=true
autorestart=true
stderr_logfile=/path/to/project/logs/scheduler.err.log
stdout_logfile=/path/to/project/logs/scheduler.out.log

The shell script is needed to a) load the Python virtual environment, and b) execute the management commands which queues up the jobs. For example:

#! /usr/bin/env bash

source /path/to/project/python/bin/active;
(cd /path/to/project/source && ./manage.py scheduler_run_jobs);

Creating Job Callbacks

A callback function is needed to execute a job.

The function must accept **kwargs and return an instance of superdjango.contrib.scheduler.library.Result.

# myapp/scheduler.py
from superdjango.contrib.scheduler import STATUS, Result

def do_something_on_a_recurring_basis(**kwargs):
    # do some work ...
    return Result(
        STATUS.SUCCESS,
        message="This may be displayed to a user.",
        output="This may be displayed to administrators or developers."
    )

The label and start/end datetimes are automatically set at runtime.

With manual configuration this callback would be added to the scheduler.ini file like so:

[do something on a recurring basis]
callback = myapp.scheduler.do_something_on_a_recurring_basis
description = It's good practice to include a description, but it will default to the callback's docstring.
every = 5 minutes

When auto-discovery is configured, you must also register the callback:

# myapp/scheduler.py
from superdjango.contrib.scheduler import STATUS, Result, schedule

def do_something_on_a_recurring_basis(**kwargs):
    # do some work ...
    return Result(
        STATUS.SUCCESS,
        message="This may be displayed to a user.",
        output="This may be displayed to administrators or developers."
    )

schedule.register("myapp", do_something_on_a_recurring_basis)

Creating Activity Records

When auto-discovery is enabled, it is up to the developer to create the activity records for a given job.

from superdjango.contrib.scheduler import STATUS, Result, schedule
from superdjango.contrib.scheduler.models import Activity

def do_something_on_a_recurring_basis(**kwargs):
    job_id = kwargs.pop("pk", None)

    # do some work ...

    result = Result(
        STATUS.SUCCESS,
        message="This may be displayed to a user.",
        output="This may be displayed to administrators or developers."
    )

    if job_id:
        Activity.log(job_id, result)

    return result

schedule.register("myapp", do_something_on_a_recurring_basis)

Setting Up the INI Export

A simple cron job may be used to set up the regular export of auto-configured the INI file:

# /etc/cron.d/project_name
SHELL=/bin/bash
PATH=/path/to/project/python/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# Times are in UTC. Starts at 4am EST.
0 8 * * 0 root /path/to/project/cron/export_scheduler_ini.sh

And the script itself:

#! /usr/bin/env bash

source /path/to/project/python/bin/active;
(cd /path/to/project/source && ./manage.py scheduler_run_jobs);

Multi-Tenant Considerations for Scheduled Jobs

In a multi-tenant environment, scheduled jobs may need to be specific to each tenant. When using WSGI for tenant separation, there are fewer concerns with data separation, but a scheduler for each tenant must be maintained.

To accomplish this, a separate scheduler.ini file is required for each tenant. We suggest creating this in the tenant’s directory, such as /path/to/example_app/shared/tenants/acme_example_app/config/scheduler.ini.

With manual configuration, simply create or copy the file to the appropriate location.

Or with auto configuration, this is easily accomplished using preview and bash output redirection:

# from project root with virtual env activated
./manage.py scheduler_export_ini \
--settings=tenants.acme_example_app.settings \
-p > tenants/acme_example_app/config/scheduler.ini;

This assumed job discovery has already been performed with:

./manage.py scheduler_discover_jobs --settings=tenants.acme_example_app.settings;

Listing jobs requires specifying the path, as in:

./manage.py scheduler_list_jobs -P tenants/acme_example_app/config/scheduler.ini;

The supervisord configuration may be exported using a tenant-specific name:

./manage.py scheduler_export_supervisord \
/path/to/example_app/shared/tenants/acme_example_app/cron/scheduler.sh \
-w -n acme_example_app;

And the cron script would look something like:

#! /usr/bin/env bash

source /path/to/example_app/current/python/bin/active;
(cd /path/to/example_app/current/source && ./manage.py scheduler_run_jobs \
--settings=tenants.acme_example_app.settings \
-P tenants/acme_example_app/config/scheduler.ini);

Support

experimental app

Version: 0.3.1-x

Provides management support or help content from within a project.

Developer Reference: Support

Provides

Dependencies

  • markdown (required) Used to generate support/help docs from Markdown files.

  • python-frontmatter (required) Parses meta data from Markdown files.

  • pyyaml (required) Currently only used for the ScannerError exception that may be emitted by frontmatter.

Install

Install requirements:

pip install Markdown python-frontmatter pyyaml;

Add superdjango.contrib.support.apps.DefaultConfig to INSTALLED_APPS.

Add the static directory to the STATICFILES_DIRS list:

STATICFILES_DIRS = [
    # ...
    os.path.join(BASE_DIR, "../help", "static"),
]

Optionally configure the following settings:

# Markdown extensions for rendering article content.
SUPERDJANGO_SUPPORT_MD_EXTENSIONS = ["extra"]

# The path to help content.
SUPERDJANGO_SUPPORT_PATH = os.path.join(BASE_DIR, "../help")

# Indicates whether unauthenticated users can access help content.
SUPERDJANGO_SUPPORT_REQUIRES_LOGIN = True

# Indicates search results should be logged. Helps improve the search catalog.
SUPERDJANGO_SUPPORT_SEARCH_LOG_RESULTS = True

# A list of terms that may be used to build the search catalog.
SUPERDJANGO_SUPPORT_SEARCH_TERMS = list()

Add URLs:

urlpatterns = [
    # ...
    path('help/', include(superdjango.contrib.support.urls),
    # ...
]

Usage

Initialize help files and directories:

Create the help directory in project root:

./manage.py init_support_dir;

Customize the INI files and create content files as desired.