Merengue plugins are installable components that allow you to add new functionality of your site. With plugins you can add:
Django Apps vs. Merengue Plugins
There are two main differences between Django apps and Merengue plugins:
Only three steps are required to install a new plugin:
(( To be completed. Talk about media conventions taken in Merengue, merengue.views.static.serve view and sync_plugins_media command. ))
Merengue detects broken plugins found in the plugins directory. Broken plugins are shown in the plugins admin view:
Merengue detects broken plugins to avoid “breaking” the entire system (or site) when you install a third party plugin. The plugins admin view does not allow you to install broken plugins. However, if you have a broken plugin which is activated, you will get an exception – your site is “broken”.
Plugins can “break” for the following reasons:
To detect broken plugins, execute the mark_broken_plugins command, or set DETECT_BROKEN_PLUGINS setting to True (the default) and visit the plugins admin view.
To debug broken plugins, you need to access the broken plugin’s admin edit change form. In this view, Merengue will show the error traceback:
Some plugins have customization parameters which appear in the plugin admin view. See the registry configuration params topic for more details.
To write a custom plugin for Merengue, you need to create a Django application which will:
All plugins will be placed in the plugins directory located in your project directory.
A typical Merengue plugin directory structure:
/plugins/
|-- fooplugin/
| |-- __init__.py
| |-- actions.py
| |-- blocks.py
| |-- config.py
| |-- models.py
| |-- views.py
| |-- viewlets.py
| |-- urls.py
| `-- templates/
| `-- fooplugin/
| `-- media/
| `-- fooplugin/
|
...
Note
Only the __init__.py and config.py files are mandatory.
Let's explain piece of the directory tree listed above:
as a python module.
models.py is a normal Django application model file. See the base models documentation to get more information on the Merengue base models which you can extend in your own plugin(s).
config.py is the configuration file for the plugin. See the plugin configuration reference documentation.
blocks.py is a Merengue blocks file which contains the code for the new, visually oriented blocks defined in your plugin.
actions.py is a Merengue actions file.
views.py is normal Django views file.
urls.py is normal Django urls file. You can use it to control a URL namespace (i.e. all /fooplugin/.* urls).
templates/fooplugin/ is a directory for fooplugin template resources.
media/fooplugin/ is a directory for media resources (e.g. icons, css, etc.)
A plugin configuration is defined in the PluginConfig class located in the config.py module inside your plugin directory. This class is read by Merengue when the plugin is loaded initially.
A code fragment from a config.py example:
from merengue.pluggable import Plugin
class PluginConfig(Plugin):
name = "Foo plugin"
url_prefixes = (
('fooplugin', 'plugins.fooplugin.urls'),
)
def get_actions(self):
return [...]
def get_blocks(self):
return [...]
def section_models(self):
return [...]
# ... etcetera
The name parameter is used to give the plugin a name (visible in the Merengue plugin control center). It's a required parameter and usually consists of a single word (or two).
The description parameter adds additional information for the plugin. It can be a full sentence, describing the plugin, giving the Merengue administrator an idea of the plugin's purpose and its functionality.
Finally, the version parameter is a string with version information for the plugin. This parameter is not required, however its usage is highly recommended.
An example:
class PluginConfig(Plugin):
name = "Foo"
description = "Demo plugin to explain how to create Merengue plugins"
version = "1.0.0"
The url_prefixes parameter contains the URL prefix for all of your plugin URLs.
Example:
class PluginConfig(Plugin):
url_prefixes = (
('fooplugin', 'plugins.fooplugin.urls'),
...
)
In this example, if the plugin was activated, all URLs below fooplugin will be handled by the plugins.fooplugin.urls module. Internally, the Merengue plugin system will perform an operation like this:
urlpatterns += patterns('',
(r'^fooplugin/', include('plugins.fooplugin.urls')),
)
You can also internationalize your plugin's URLs. See this example:
class PluginConfig(Plugin):
# ... stuff
url_prefixes = (
({'en': 'event', 'es': 'eventos'},
'plugins.event.urls'),
)
The final URL prefix used will depend on the URL_DEFAULT_LANG setting (by default it will be set the same as LANGUAGE_CODE).
Note
Your site will have only one prefix for every url prefixes you have internazionalized. So, if your URL_DEFAULT_LANG is "es", only /eventos will be handled for the plugin and /event will raise a 404 error.
A developer can do many things when developing a new plugin:
Define new blocks: Implement the get_blocks(self) method in the PluginConfig class. See the blocks reference for more information.
An example:
from plugins.fooplugin.blocks import FooBlock
class PluginConfig(Plugin):
# stuff ...
def get_blocks(self):
return [FooBlock, ]
Define new actions: Implement the get_actions(self) method in the PluginConfig class. See the actions reference for more information.
An example:
from plugins.fooplugin.actions import FooAction
class PluginConfig(Plugin):
# stuff ...
def get_actions(self):
return [FooAction, ]
Create new models: Implement new models in the plugin models.py file.
An example:
from merengue.base.models import BaseContent
class FooContent(BaseContent):
new_field = models.CharField(max_length=100)
# stuff ...
Define a plugin's custom admin site: Implement the get_model_admins(self) method in the PluginConfig class.
An example:
from plugins.fooplugin.admin import FooContentAdmin, FooCategoryAdmin
from plugins.fooplugin.models import FooContent, FooCategory
class PluginConfig(Plugin):
# stuff ...
def get_model_admins(self):
return [(FooContent, FooContentAdmin),
(FooCategory, FooCategoryAdmin)]
Define new permissions: Implement the get_perms(self) method in the PluginConfig class. See the permissions reference for more information.
An example:
from plugins.forum.models import FooContent
class PluginConfig(Plugin):
# stuff ...
def get_perms(self):
return [('Vote foo', 'vote_foo', [FooContent]), ), ]
Define new viewlets: Implement the get_viewlets(self) method in the PluginConfig class. See the viewlets reference for more information.
An example:
from plugins.fooplugin.viewlets import FooViewlet1, FooViewlet2
class PluginConfig(Plugin):
# stuff ...
def get_viewlets(self):
return [FooViewlet1, FooViewlet2]
Define new middleware: Implement the get_middlewares(self) method in the PluginConfig class. See the Django middleware reference for more information.
An example:
class PluginConfig(Plugin):
# stuff ...
def get_middlewares(self):
return ['plugins.fooplugin.middleware.FooMiddleware', ]
Execute code after plugin activation: Implementing the hook_post_register(self) method in the PluginConfig class.
An example:
from django.core.mail import send_mail
class PluginConfig(Plugin):
# stuff ...
def hook_post_register(self):
send_mail('Foo plugin enabled', 'The foo plugin has been enabled.', 'from@example.com',
'admin@example.com', fail_silently=True)
Check out the Merengue plugins directory to see several plugin implementations (e.g. the news plugin).
Sometimes your project depends on a plugin (or multiple plugins) to be activated by default and you want to prevent the user from deactivating it (or them). For example, your project logic may rely on the existence of certains models defined in a specific plugin.
You can define which plugins your project depends on by including the following setting in your project settings:
REQUIRED_PLUGINS = ('core', 'fooplugin', )
Default: ('core', ) (the core plugin)
About the core plugin:
The core plugin must be included in the REQUIRED_PLUGINS setting for all of the standard Merengue features to be present in your site.
After changing the REQUIRED_PLUGINS setting, you will need to register the plugin with the following command to get new plugins activated (and also to get their models created if any exist):
python manage.py migrate
If your plugin's models change, and you want a clean model migration for your site(s), you may need to implement South migrations for it.
In order to create South migrations, you have to use the schemamigration and datamigration commands (see the South docs for more information). You only have to remember to temporarily add the plugin name to the INSTALLED_APPS setting before executing thesecommands, because South is not able to find Merengue plugins on its own.
When a plugin with a South migration setup is installed, Merengue will automatically execute the plugin's South migrations.
To execute an existing (i.e. installed) plugin's South-based migration, you must uninstall and re-install the plugin using the Merengue admin site.
Also, you can use the very helpful migrate_plugins command which migrates all installed, enabled plugins in your site. The following lines illustrate how to use the migrate-plugins command:
$ python manage.py migrate_plugins # migrate all enabled plugins
$ python manage.py migrate_plugins --list # show migration list of enabled plugins
$ python manage.py migrate_plugins forum # migrate only forum plugin, if enabled
$ python manage.py migrate_plugins forum 0002 # migrate only 0002* step for forum plugin
$ python manage.py migrate_plugins forum 0001_initial # fakes 0001_initial step for forum plugin
Jul 01, 2011