Tutorial¶
Install¶
Either install the last release:
pip install django-rules-light
Either install a development version:
pip install -e git+https://github.com/yourlabs/django-rules-light.git#egg=django-rules-light
That should be enough to work with the registry.
Middleware¶
To enable the middleware that processes rules_light.Denied
exception, add to setings.MIDDLEWARE_CLASSES
:
MIDDLEWARE_CLASSES = (
# ...
'rules_light.middleware.Middleware',
)
See docs on middleware for more details.
Autodiscovery¶
To enable autodiscovery of rules in the various apps installed
in your project, add to urls.py
(as early as possible):
import rules_light
rules_light.autodiscover()
See docs on registry for more details.
Logging¶
To enable logging, add a rules_light
logger for example:
LOGGING = {
# ...
'handlers': {
# ...
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'rules_light': {
'handlers': ['console'],
'propagate': True,
'level': 'DEBUG',
}
}
}
See docs on logging for more details on logging.
Debug view¶
Add to settings.INSTALLED_APPS
:
INSTALLED_APPS = (
'rules_light',
# ....
)
Then the view should be usable, install it as such:
url(r'^rules/', include('rules_light.urls')),
See docs on debugging for more details on debugging rules.
Creating Rules¶
Declare rules¶
Declaring rules consist of filling up the rules_light.registry
dict. This
dict uses rule “names” as keys, ie. do_something
,
some_app.some_model.create
, etc, etc … For values, it can use booleans:
# Enable read for everybody
rules_light.registry['your_app.your_model.read'] = True
# Disable delete for everybody
rules_light.registry['your_app.your_model.delete'] = False
Optionnaly, use the Python dict method setdefault()
in default rules. For
example:
# Only allow everybody if another (project-specific) callback was not set
rules_light.registry.setdefault('your_app.your_model.read', True)
It can also use callbacks:
def your_custom_rule(user, rule_name, model, *args, **kwargs):
if user in model.your_custom_stuff:
return True # Allow user !
rules_light.registry['app.model.read'] = your_custom_rule
See docs on registry for more details.
Mix rules, DRY security¶
Callbacks may also be used to decorate each other, using
rules_light.make_decorator()
will transform a simple rule callback, into a
rule callback that can also be used as decorator for another callback.
Just decorate a callback with make_decorator()
to make it reusable as
decorator:
@rules_light.make_decorator
def some_condition(user, rule, *args, **kwargs):
# do stuff
rules_light.registry.setdefault('your_app.your_model.create', some_condition)
@some_condition
def extra_condition(user, rule, *args, **kwargs):
# do extra stuff
rules_light.registry.setdefault('your_app.your_model.update', extra_condition)
This will cause some_condition()
to be evaluated first, and if it passes,
extra_condition()
will be evaluated to, for the update rule.
See docs on decorator for more details.
Using rules¶
The rule registry is in charge of using rules, using the run()
method. It
should return True or False.
Run¶
For example with this:
def some_condition(user, rulename, *args, **kwargs):
# ...
rules_light.registry['your_app.your_model.create'] = some_condition
Doing:
rules_light.run(request.user, 'your_app.your_model.create')
Will call:
some_condition(request.user, 'your_app.your_model.create')
Kwargs are forwarded, for example:
rules_light.run(request.user, 'your_app.your_model.create',
with_widget=request.GET['widget'])
Will call:
some_condition(request.user, 'your_app.your_model.create',
with_widget=request.GET['widget'])
See docs on registry for more details.
Require¶
The require()
method is useful too, it does the same as run()
except
that it will raise rules_light.Denied
. This will block the request process
and will be catched by the middleware if installed.
See docs on registry for more details.
Decorator¶
You can decorate a class based view as such:
@rules_light.class_decorator
class SomeCreateView(views.CreateView):
model=SomeModel
This will automatically require 'some_app.some_model.create'
.
See docs on class decorator for more usages of the decorator.
Template¶
In templates, you can run rules using ‘{% rule %}’ templatetag.
Usage:
{% rule rule_name [args] [kwargs] as var_name %}
This is an example from the test project:
{% load rules_light_tags %}
<ul>
{% for user in object_list %}
{% rule 'auth.user.read' user as can_read %}
{% rule 'auth.user.update' user as can_update %}
<li>
<a href="{% url 'auth_user_detail' user.username %}">{{ user }} (has perm: {{ can_read|yesno:'Yes,No' }})</a>
<a href="{% url 'auth_user_update' user.username %}">update (has perm: {{ can_update|yesno:'Yes,No'}})</a>
</li>
{% endfor %}
</ul>
Tips and tricks¶
Override rules¶
If your project wants to change the behaviour of your_app
to allows users
to create models and edit the models they have created, you could add after
rules_light.autodiscover()
:
def my_model_or_staff(user, rulename, obj):
return user.is_staff or user == obj.author
rules_light.registry['your_app.your_model.create'] = True
rules_light.registry['your_app.your_model.update'] = my_model_or_staff
rules_light.registry['your_app.your_model.delete'] = my_model_or_staff
As you can see, a project can completely change the security logic of an app, which should enpower creative django developers hehe …
See docs on registry for more details.
Take a shortcut¶
django-rules-light comes with a predefined is_staff
rule which you could
use in your_app/rules_light_registry.py
:
import rules_light
# Allow all users to see your_model
rules_light.registry.setdefault('your_app.your_model.read', True)
# Allow admins to create and edit models
rules_light.registry.setdefault('your_app.your_model.create', rules_light.is_staff)
rules_light.registry.setdefault('your_app.your_model.update', rules_light.is_staff)
rules_light.registry.setdefault('your_app.your_model.delete', rules_light.is_staff)
See docs on shortcuts.