Molly extends Django by formalising the concept of an application. This is acheived by instantiating Application objects and adding then to APPLICATIONS in your settings module.
This document explains how the Application framework works, and should not be a necessary part of your reading unless you intend to write a new Molly application, or have sufficient levels of curiosity.
If you don’t know whether you want to write an application or a provider, the following section may be useful. For information on writing providers, see topics/writing_providers.
Molly is intended to be relatively pluggable, allowing the deploying institution to take whatever provided functionality they choose and, if necessary, integrate it with their own applications.
This integration can be done at two levels, the application level, or the provider level.
An application is a Python package, usually containing urls, models and views modules. An application provides a data model and interface for a particular class of information, for example, PC availability or lecture timetables.
A provider is usually a single Python class that connects an application to a data source. A provider might implement some well-known protocol or file format (e.g. RSS for the feeds application), or might connect to a local bespoke system.
It is intended that in the majority of cases the implementor should be able to take an already-existing application and need only write the provider that performs the interaction with other systems.
An Application object is a wrapper around a Python package which hooks in providers and configuration objects for easy access by the application. The definition is as follows:
Instantiates an Application object. None of the module or package paths are dereferenced yet. kwargs are mostly left alone and attached to the ~molly.conf.settings.ApplicationConf class. Some, defined later, have special meanings.
Parameters: |
|
---|
Used internally. Creates a configuation object and dereferences all the paths provided to it. Where a urls module exists it will call add_conf_to_pattern() to walk the urlconf to attach the configuration object to the views.
The ApplicationConf returned will have attributes reflecting the kwargs passed to __init__(). The urlconf will be exposed as a urls attribute.
Return type: | ApplicationConf subclass |
---|
Used internally. Maps the conf and bases onto the views contained in pattern. This method creates a new view, with conf in the class dictionary and the view and bases as base classes. Specifically:
new_callback = type(callback.__name__ + 'WithConf',
(callback,) + bases,
{ 'conf': conf })
This dynamically creates a new class object. For more information, see the second definition of type().
When given a RegexURLPattern it will return a new RegexURLPattern with its callback replaced as above. When given a RegexURLResolver it will descend recursively before returning a new RegexURLResolver instance.
Returns: | A copy of the first argument with views replaced as described above. |
---|---|
Return type: | RegexURLResolver or RegexURLPattern instance |
In the vast majority of cases, you will only need to use the constructor, and only in your settings module.
There are a few keyword arguments with special meanings:
Here’s an example:
APPLICATIONS = [
# ...
Application('example.apps.dictionary', 'dictionary', 'Dictionary',
provider = Provider('isihac.providers.apps.dictionary.uxbridge'),
max_results = 10,
),
# ...
]
Here we want to use a dictionary application with at most ten results from the Uxbridge English Dictionary. If we wanted to expose two different dictionaries we may wish to do the following:
APPLICATIONS = [
# ...
Application('example.apps.dictionary', 'uxbridge_dictionary', 'Uxbridge English Dictionary',
provider = Provider('isihac.providers.apps.dictionary.uxbridge'),
max_results = 10,
),
Application('example.apps.dictionary', 'oxford_dictionary', 'Oxford English Dictionary',
provider = Provider('oxford.providers.apps.dictionary.oed'),
max_results = 20,
),
# ...
]
Once hooked into the root urlconf, this would present two links on the home page. Alternatively, if the example.apps.dictionary application supported multiple providers, we could do this:
APPLICATIONS = [
# ...
Application('example.apps.dictionary', 'dictionary', 'Dictionaries',
providers = (
Provider('isihac.providers.apps.dictionary.uxbridge',
slug='uxbridge',
title='Uxbridge English Dictionary'),
Provider('oxford.providers.apps.dictionary.oed',
slug='oed',
title='Oxford English Dictionary'),
),
max_results = 10,
),
# ...
]
Of course, this assumes that the application knows to pick the slug and title from each of its providers. To determine the interface between applications and providers, consult the application’s documentation.
A provider maps an external interface onto the model used by the application.
Most applications provide a providers.BaseProvider class which specifies an interface to be implemented by a provider for that application.
A provider can annotate methods to be included in a crontab using the molly.conf.settings.batch() decorator:
@batch('%d 9 * * mon' % random.randint(0, 59))
def import_data(self, metadata, output):
# do stuff
return metadata
For more information, see topics/batch_jobs.