A plugin system for django.
Project description
django-hooks
============
A plugin system for django apps. It provides ways for an app to inject
code into another app. So you can integrate existing apps into your main
app. I call this existing app an *App-Hook*.
There are 3 kinds of hooks:
- TemplateHook: the most useful one, App-Hooks will be able to inject
their own code into your templates.
- ViewHook: App-Hooks will be able to add Forms in your views.
- SignalHook: This is the same as django signals except that
*signal-hooks* don’t need to be pre-created. You can connect or emit
a signal by its name/id.
**Tested** in Django 1.4, 1.5, 1.6; Python 2.7, 3.4
Configuration
-------------
1. Add ``hooks`` to your *INSTALLED\_APPS*. This is required only if you
are going to use the templatetags.
Learn by example
----------------
TemplateHook
~~~~~~~~~~~~
Adding a hook in your main-app template:
.. code:: html
# main_app/templates/_base.html
{% load hooks_tags %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
#...
{% hook 'within_head' %}
#...
</head>
</html>
Here we are adding a *hook point* called ``within_head`` where App-Hooks
will be able to inject their code.
Creating a hook in your App-Hook:
.. code:: python
# app_hook/templatehooks.py
from django.template.loader import render_to_string
def css_resources(context, *args, **kwargs):
return u'<link rel="stylesheet" href="%s/app_hook/styles.css">' % settings.STATIC_URL
def a_more_complex_hook(context, *args, **kwargs):
# If you are doing this a lot, make sure to keep your templates in memory (google: django.template.loaders.cached.Loader)
return render_to_string('templates/app_hook/head_resources.html', context_instance=context)
def a_even_more_complex_hook(context, *args, **kwargs):
articles = Article.objects.all()
return render_to_string('templates/app_hook/my_articles.html', {'articles': articles, }, context_instance=context)
Registering a hook in your App-Hook:
.. code:: python
# app_hook/urls.py
from app_hook.templatehooks import css_resources
from hooks.templatehook import hook
hook.register("within_head", css_resources)
**Note**
Where to register your hooks:
urls.py is a good place (django<=1.6)
or do it in the AppConfig.ready() method (django>=1.7)
ViewHook
~~~~~~~~
Creating a view-hook:
.. code:: python
# main_app/viewhooks.py
from hooks.viewhook import Hook
myview = Hook()
Adding it to your view:
.. code:: python
# main_app/views.py
from main_app import viewhooks
def myview(request):
#...
hook = hooks.myview(request)
hook.dispatch()
if is_post:
#...
hook.post()
if hook.is_valid():
#...
hook.save()
redirect('/')
else:
#...
hook.get()
context = {'foo': foobar, }
context.update(hook.context)
return response(context) #...
**Note** See Miscellaneous for a real life example.
Creating a hook in your App-Hook:
.. code:: python
# app_hook/viewhooks.py
from hooks.viewhook import HookBase
class MyHook(HookBase):
def dispatch(*args, **kwargs):
# do something useful
def post(*args, **kwargs):
form = MyForm(data=self.request.POST)
self.context['myhookform'] = form
def is_valid():
return self.context['myhookform'].is_valid()
def save(*args, **kwargs):
self.context['myhookform'].save()
def get(*args, **kwargs):
form = MyForm()
self.context['myhookform'] = form
Registering a view-hook:
.. code:: python
# app_hook/urls.py
from app_hook.viewhooks import MyHook
from main_app import viewhooks
viewhooks.myview.register(MyHook)
SignalHook
~~~~~~~~~~
Connecting a signal-hook:
.. code:: python
# app_hook/urls.py
from app_hook.viewhooks import myhandler
from hooks import signalhook
signalhook.hook.connect("my-signal", myhandler)
Sending a signal:
.. code:: python
# send from anywhere, app-hook, main-app... view, model, form...
from hooks import signalhook
signalhook.hook.send("my-signal", myarg="a string", mykwarg={'somthing': "else", })
signalhook.hook.send("another-signal")
**Note** SignalHook uses django signals under the hook, so you can
do pretty much the same.
Miscellaneous
~~~~~~~~~~~~~
As you saw earlier *TemplateHooks* don’t need to be pre-created, passing
``within_head`` to hook will call any callback previously registered to
that name/id. But, what if you want to have static/pre-created
template-hooks… you can! but it requires you to create an extra template
tag. Let’s create a static template-hook:
.. code:: python
# main_app/templatehooks.py
from hooks.templatehook import TemplateHook
within_head = TemplateHook(providing_args=["context", ])
Now, we can’t use the ``hooks_tags``, that’s only good for dynamic
template-hooks! What we need is to create our own tag that will call the
``within_head`` from our ``hooks.py`` module.
.. code:: python
# main_app/templatetags/hook.py
from hooks.templatetags import template_hook_collect
from main_app import hooks
@register.simple_tag(takes_context=True)
def hook(context, name, *args, **kwargs):
return template_hook_collect(hooks, name, context, *args, **kwargs)
In your template:
.. code:: html
# main_app/templates/_base.html
{% load hook %}
<html>
<head>
{% hook 'within_head' %}
...
Registering in your App-Hook:
.. code:: python
app_hook/urls.py
from app_hook.templatehooks import css_resources
from main_app.templatehooks import within_head
within_head.register(css_resources)
Now, a real life viewhook example:
.. code:: python
main_app/views.py
from main_app import viewhooks
from main_app.form import UserForm
def myview(request, article_id):
article = Article.objects.get(pk=article_id)
hook = hooks.myview(request)
hook.dispatch(article)
if request.method == 'POST':
form = UserForm(data=request.POST)
hook.post(article)
if form.is_valid() and hook.is_valid():
user = form.save()
hook.save(user)
redirect('/')
else:
form = UserForm()
hook.get()
context = {'form': form, }
context.update(hook.context)
return render(request, 'main_app/my_template.html', context)
Contributing
------------
Feel free to check out the source code and submit pull requests.
You may also report any bug or propose new features in the `issues
tracker`_
Copyright / License
-------------------
Copyright 2014 `Esteban Castro Borsani`_.
Licensed under the `MIT License`_.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============
A plugin system for django apps. It provides ways for an app to inject
code into another app. So you can integrate existing apps into your main
app. I call this existing app an *App-Hook*.
There are 3 kinds of hooks:
- TemplateHook: the most useful one, App-Hooks will be able to inject
their own code into your templates.
- ViewHook: App-Hooks will be able to add Forms in your views.
- SignalHook: This is the same as django signals except that
*signal-hooks* don’t need to be pre-created. You can connect or emit
a signal by its name/id.
**Tested** in Django 1.4, 1.5, 1.6; Python 2.7, 3.4
Configuration
-------------
1. Add ``hooks`` to your *INSTALLED\_APPS*. This is required only if you
are going to use the templatetags.
Learn by example
----------------
TemplateHook
~~~~~~~~~~~~
Adding a hook in your main-app template:
.. code:: html
# main_app/templates/_base.html
{% load hooks_tags %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
#...
{% hook 'within_head' %}
#...
</head>
</html>
Here we are adding a *hook point* called ``within_head`` where App-Hooks
will be able to inject their code.
Creating a hook in your App-Hook:
.. code:: python
# app_hook/templatehooks.py
from django.template.loader import render_to_string
def css_resources(context, *args, **kwargs):
return u'<link rel="stylesheet" href="%s/app_hook/styles.css">' % settings.STATIC_URL
def a_more_complex_hook(context, *args, **kwargs):
# If you are doing this a lot, make sure to keep your templates in memory (google: django.template.loaders.cached.Loader)
return render_to_string('templates/app_hook/head_resources.html', context_instance=context)
def a_even_more_complex_hook(context, *args, **kwargs):
articles = Article.objects.all()
return render_to_string('templates/app_hook/my_articles.html', {'articles': articles, }, context_instance=context)
Registering a hook in your App-Hook:
.. code:: python
# app_hook/urls.py
from app_hook.templatehooks import css_resources
from hooks.templatehook import hook
hook.register("within_head", css_resources)
**Note**
Where to register your hooks:
urls.py is a good place (django<=1.6)
or do it in the AppConfig.ready() method (django>=1.7)
ViewHook
~~~~~~~~
Creating a view-hook:
.. code:: python
# main_app/viewhooks.py
from hooks.viewhook import Hook
myview = Hook()
Adding it to your view:
.. code:: python
# main_app/views.py
from main_app import viewhooks
def myview(request):
#...
hook = hooks.myview(request)
hook.dispatch()
if is_post:
#...
hook.post()
if hook.is_valid():
#...
hook.save()
redirect('/')
else:
#...
hook.get()
context = {'foo': foobar, }
context.update(hook.context)
return response(context) #...
**Note** See Miscellaneous for a real life example.
Creating a hook in your App-Hook:
.. code:: python
# app_hook/viewhooks.py
from hooks.viewhook import HookBase
class MyHook(HookBase):
def dispatch(*args, **kwargs):
# do something useful
def post(*args, **kwargs):
form = MyForm(data=self.request.POST)
self.context['myhookform'] = form
def is_valid():
return self.context['myhookform'].is_valid()
def save(*args, **kwargs):
self.context['myhookform'].save()
def get(*args, **kwargs):
form = MyForm()
self.context['myhookform'] = form
Registering a view-hook:
.. code:: python
# app_hook/urls.py
from app_hook.viewhooks import MyHook
from main_app import viewhooks
viewhooks.myview.register(MyHook)
SignalHook
~~~~~~~~~~
Connecting a signal-hook:
.. code:: python
# app_hook/urls.py
from app_hook.viewhooks import myhandler
from hooks import signalhook
signalhook.hook.connect("my-signal", myhandler)
Sending a signal:
.. code:: python
# send from anywhere, app-hook, main-app... view, model, form...
from hooks import signalhook
signalhook.hook.send("my-signal", myarg="a string", mykwarg={'somthing': "else", })
signalhook.hook.send("another-signal")
**Note** SignalHook uses django signals under the hook, so you can
do pretty much the same.
Miscellaneous
~~~~~~~~~~~~~
As you saw earlier *TemplateHooks* don’t need to be pre-created, passing
``within_head`` to hook will call any callback previously registered to
that name/id. But, what if you want to have static/pre-created
template-hooks… you can! but it requires you to create an extra template
tag. Let’s create a static template-hook:
.. code:: python
# main_app/templatehooks.py
from hooks.templatehook import TemplateHook
within_head = TemplateHook(providing_args=["context", ])
Now, we can’t use the ``hooks_tags``, that’s only good for dynamic
template-hooks! What we need is to create our own tag that will call the
``within_head`` from our ``hooks.py`` module.
.. code:: python
# main_app/templatetags/hook.py
from hooks.templatetags import template_hook_collect
from main_app import hooks
@register.simple_tag(takes_context=True)
def hook(context, name, *args, **kwargs):
return template_hook_collect(hooks, name, context, *args, **kwargs)
In your template:
.. code:: html
# main_app/templates/_base.html
{% load hook %}
<html>
<head>
{% hook 'within_head' %}
...
Registering in your App-Hook:
.. code:: python
app_hook/urls.py
from app_hook.templatehooks import css_resources
from main_app.templatehooks import within_head
within_head.register(css_resources)
Now, a real life viewhook example:
.. code:: python
main_app/views.py
from main_app import viewhooks
from main_app.form import UserForm
def myview(request, article_id):
article = Article.objects.get(pk=article_id)
hook = hooks.myview(request)
hook.dispatch(article)
if request.method == 'POST':
form = UserForm(data=request.POST)
hook.post(article)
if form.is_valid() and hook.is_valid():
user = form.save()
hook.save(user)
redirect('/')
else:
form = UserForm()
hook.get()
context = {'form': form, }
context.update(hook.context)
return render(request, 'main_app/my_template.html', context)
Contributing
------------
Feel free to check out the source code and submit pull requests.
You may also report any bug or propose new features in the `issues
tracker`_
Copyright / License
-------------------
Copyright 2014 `Esteban Castro Borsani`_.
Licensed under the `MIT License`_.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
django-hooks-0.1.0.tar.gz
(9.1 kB
view details)
File details
Details for the file django-hooks-0.1.0.tar.gz
.
File metadata
- Download URL: django-hooks-0.1.0.tar.gz
- Upload date:
- Size: 9.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | a7e6c8d70fd9e27cfc4bb860c26b7302e1b2dbeb4415b7f5713e335cca71c363 |
|
MD5 | 0e9acfac75b8f6b1e0ca1957a354e08b |
|
BLAKE2b-256 | 90d0542ae4385cd60d6b147222b0496d74f6d89499f5ffe16bc3823fb9af5307 |