Quickstart

Dependencies

  • django >= 2.2

Installation

  1. Install the latest tarball:

    pip install https://git.m-stelzer.de/knoppo/django-model-permissions/-/archive/master/django-model-permissions-master.tar.gz
    
  2. Add the app to INSTALLED_APPS:

    INSTALLED_APPS = [
        # ...
        'model_permissions',
    ]
    
  3. Replace AUTHENTICATION_BACKENDS:

    AUTHENTICATION_BACKENDS = [
        'model_permissions.backends.ObjectModelBackend',
    ]
    

    This replaces the default backend with an extended version. (See Permission Function)

    If you don’t want to retain django’s user and group permissions, use the ObjectBackend instead:

    AUTHENTICATION_BACKENDS = [
        'model_permissions.backends.ObjectBackend',
    ]
    
  4. Optional: Redirect all PermissionDenied errors to LOGIN_URL:

    MIDDLEWARE = [
        # ...
        'model_permissions.middleware.RedirectMiddleware',
    ]
    

Usage

  1. Create a Permission Function called get_permissions as a method on your model:

    It should return a list of permissions the given user has for this object.

    class MyModel(models.Model):
        owner = models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE)
    
        def get_permissions(self, user):
            if user.is_anonymous:
                return
    
            permissions = ['myapp.add_mymodel']
    
            if not user.is_staff and not user == self.owner:
                return permissions
    
            return permissions + [
                'myapp.change_mymodel',
                'myapp.delete_mymodel',
            ]
    
  2. Use the model_permissions views or mixins:

    Since it seems to be very hard to inject the object permissions in a context_processor, django-model-permissions comes with ready-to-use views and mixins:

    from model_permissions.views import CreateView, UpdateView, DeleteView
    
    class MyModelCreateView(CreateView):
        model = MyModel
    
    class MyModelCreateView(UpdateView):
        model = MyModel
        fields = ('name', 'description', 'owner')
        required_permission = 'myapp.change_mymodel'
    
    class MyModelCreateView(DeleteView):
        model = MyModel
        required_permission = 'myapp.delete_mymodel'
    

    The main functionality is split into 2 mixins.

    Tip

    Use the model_permissions.views.PermissionMixin if you want both.

    The model_permissions.views.PermissionContextMixin adds a 'object_perms' variable to the template context. Use it if your view is public and you just want to access the permissions in the template.

    from model_permissions.views import PermissionContextMixin
    from django.views.generic import DetailView
    from myapp.models import MyModel
    
    class MyModelDetailView(PermissionContextMixin, DetailView):
        model = MyModel
        fields = ('name', 'description', 'owner')
    

    Use the model_permissions.views.RequirePermissionMixin to restrict access to a view based on object permissions:

    from model_permissions.views import UpdateView
    from myapp.models import MyModel
    
    class MyModelDetailView(UpdateView):
        model = MyModel
        required_permission = 'myapp.change_mymodel'
        fields = ('name', 'description', 'owner')
    
  3. Use permissions in your templates:

    If you’re using the model_permissions.views.PermissionContextMixin or one of its subclasses your context will contain object_perms and <model_label>_perms variables:

    Note

    The second example also shows the usage of Related Permissions.

    {# forum_detail.html #}
    
    {% if forum_perms.myforum.change_forum %}
        <a href="{% url "myforum:change_forum" forum.pk %}">Edit</a>
    {% endif %}
    
    {# or #}
    
    {% if object_perms.myforum.add_thread %}
        <a href="{% url "myforum:add_thread" forum.pk %}">Add Thread</a>
    {% endif %}
    

    To get permissions for another object or in views that are not subclassing model_permissions.views.PermissionContextMixin you can use the get_perms template tag:

    Without argument it will use the object variable in the context. The resulting perms lookup dict will not contain any object permissions if there is no object.

    {# thread_detail.html #}
    
    {% load model_permissions %}
    
    {% get_perms as thread_perms %}
    
    <h1>
    {% if thread_perms.myforum.change_thread %}
    
        <a href="{% url "myforum:change_thread" thread.pk %}">{{ thread }}</a>
    
    {% else %}
    
        {{ thread }}
    
    {% endif %}
    </h1>
    
    <ul>
    {% for post in posts %}
        {% get_perms post as post_perms %}
    
        <li>
            <h4>
            {% if post_perms.myforum.change_post %}
    
                <a href="{% url "myforum:change_post" post.pk %}">{{ post }}</a>
    
            {% else %}
    
                {{ post }}
    
            {% endif %}
            </h4>
    
            <p>{{ post.text }}</p>
    
        </li>
    
    {% endfor %}
    </ul>
    

For more information see the Manual and Modules.