Contrib Apps¶
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¶
Version: 0.4.0-d
Various apps for managing user accounts.
Developer Reference: Accounts
Account Admin¶
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¶
Version: 0.7.0-a
Basic/standard user authentication via user name and/or email.
Developer Reference: Authentication
Provides
Backends
Hooks
Dependencies
python-datetime-machine (required) Used to support things like max login attempts.
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¶
Version: 0.4.0-d
Support for user avatars.
Developer Reference: Avatars
Provides
Utilities
Abstract¶
Simply implemented user avatars.
Install¶
Add superdjango.contrib.accounts.avatars.apps.DefaultConfig,
to INSTALLED_APPS
.
Usage¶
TODO: Document avatars usage examples.
User Impersonation¶
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¶
Add
'superdjango.contrib.accounts.impersonation.apps.DefaultConfig',
to yourINSTALLED_APPS
.Add
'superdjango.contrib.accounts.impersonation.middleware.UserImpersonationMiddleware',
to your list ofMIDDLEWARE
.Add
'superdjango.contrib.accounts.impersonation.context_processors.user_is_allowed_to_impersonate',
to your context processors.Add
url(r'^accounts/impersonation/', include("superdjango.contrib.accounts.impersonation.urls")),
to yoururls.py
file. (Or use AccountsViewSet.)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¶
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¶
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¶
Add
'superdjango.contrib.accounts.profiles.apps.DefaultConfig',
to yourINSTALLED_APPS
.Create your profile model by extending
ProfileModel
(orProfileMixin
).Set the
SUPERDJANGO_USER_PROFILE_MODEL
insettings.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¶
Version: 0.5.0-d
Utilities for managing user accounts.
Developer Reference: Account Utils
Provides
Utilities
Password Management¶
Version: 0.5.0-d
Additional views for user account management.
Developer Reference: Password Management
Provides
Views : viewsets
Embeds¶
Version: 0.4.0-x
An app for embedding media in a page.
Developer Reference: Embeds
Provides
Compat
Exceptions
Library
Dependencies
python-oembed (required) Required to use embed functionality.
Install¶
Install OEmbed:
pip install python-oembed;
Add 'superdjango.contrib.embeds.apps.DefaultConfig',
to INSTALLED_APPS
.
Usage¶
TODO
Error Capture¶
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¶
Add
superdjango.contrib.errors.apps.DefaultConfig
toINSTALLED_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
.
Install bitbucket-python:
pip install bitbucket-python
superdjango.contrib.errors.apps.DefaultConfig
must be included inINSTALLED_APPS
.Identify the repo using the
SUPERDJANGO_ERROR_CAPTURE_BITBUCKET_REPO
setting.Identify the owner using the
SUPERDJANGO_ERROR_CAPTURE_BITBUCKET_OWNER
setting.Provide a email using the
SUPERDJANGO_ERROR_CAPTURE_BITBUCKET_EMAIL
setting.Provide a password using the
SUPERDJANGO_ERROR_CAPTURE_BITBUCKET_PASSWORD
setting.Add
superdjango.contrib.errors.backends.Bitbucket
toSUPERDJANGO_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.
To log errors to a CSV file, add
superdjango.contrib.errors.backends.CSV
toSUPERDJANGO_ERROR_CAPTURE_HANDLERS
.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)
.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.
superdjango.contrib.errors.apps.DefaultConfig
must be included inINSTALLED_APPS
.Set the “from address” using
SUPERDJANGO_ERROR_CAPTURE_FROM_EMAIL
.Set a list of email addresses to which the info is sent using
SUPERDJANGO_ERROR_CAPTURE_EMAILS
.Add
superdjango.contrib.errors.backends.Email
toSUPERDJANGO_ERROR_CAPTURE_HANDLERS
.
GitHub Handler¶
Create a GitHub issue based on an exception.
Returns: A dictionary with the issue_url
.
Install PyGithub:
pip install PyGithub
superdjango.contrib.errors.apps.DefaultConfig
must be included inINSTALLED_APPS
.Identify the repo using the
SUPERDJANGO_ERROR_CAPTURE_GITHUB_REPO
setting.Provide a token using the
SUPERDJANGO_ERROR_CAPTURE_GITHUB_TOKEN
setting.Add
superdjango.contrib.errors.backends.GitHub
toSUPERDJANGO_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
.
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.
Add the dotted path to this model to settings using
SUPERDJANGO_ERROR_CAPTURE_MODEL_NAME
.Add
superdjango.contrib.errors.backends.GitHub
toSUPERDJANGO_ERROR_CAPTURE_HANDLERS
.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¶
Version: 0.3.0-x
An app for tracking the audit history of records in the database.
Developer Reference: History
Provides
Templates : tags
UI
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¶
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:
Form fields (and especially choices) may be customized at run time.
Choices may change with some regularity, which may generate unpredictable migrations.
See also https://docs.djangoproject.com/en/stable/topics/i18n/
Countries¶
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¶
Version: 0.2.3-p
Choices, form fields, and other resources for managing currency data.
Developer Reference: Currencies
Provides
Choices
Descriptors
Forms : fields
Languages¶
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:
Time Zones¶
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¶
Version: 0.4.0-x
Facilitates user notifications within a project, optionally sending email and SMS.
Developer Reference: Notifications
Provides
AJAX
Constants
Shortcuts
UI
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:
Define the email address from which the message is sent using
SUPERDJANGO_NOTIFICATIONS_FROM_EMAIL
.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¶
Version: 0.2.0-x
Provides support for managing project releases.
Developer Reference: Releases
Provides
Constants
Library
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¶
Version: 0.5.0-x
Provides support for scheduling jobs from the command line.
Developer Reference: Scheduler
Provides
Constants
Decorators
Library
UI
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:
Manually configuring jobs by creating an maintaining the
scheduler.ini
file.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) orno
.at
: Optional. The time of day to run the job inHH: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 infrequency 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.
To build a list of jobs in the database, run:
./manage.py scheduler_discover_jobs
Activate/deactivate jobs in the UI.
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¶
Version: 0.3.1-x
Provides management support or help content from within a project.
Developer Reference: Support
Provides
Compat
Exceptions
Library
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.