In Django, "permissions" and "authorization" are two closely related concepts that play a crucial role in controlling access to resources and actions within a web application.
full-version/
, if you wish to integrate it in starter-kit/
you can follow this documents and integrate it.
view
: Allows users to view objects of a model.add
: Allows users to create (add) objects of a model.change
: Allows users to modify (change) existing objects of a model.delete
: Allows users to delete objects of a model.The default permissions will be created for all previously-installed models, as well as for any new models being installed at that time. Afterward, it will create default permissions for new models each time you run manage.py migrate
. For more details refer Default Permission
Our application web_project
has Transaction App, and a model name is Transaction. So when we run manage.py migrate
it will create default permissions for Transaction model.
Login in to Django admin using super user credentials to verify. It will add the as shown in below image.
django.contrib.auth.models.Group
models are a generic way of categorizing users so you can apply permissions, or some other label, to those users. A user can belong to any number of groups. For more details refer Group
A user in a group automatically has the permissions granted to that group. For example, if the group Client has the permission view_transaction, any user in that group will have that permission.
Materialize provides two groups Admin and Client with different permission:
Authorization, in the context of Django, is the process of determining whether a user is allowed to perform a specific action based on the permissions they have.
@permission_required
decorator to protect a view and allow only users with specific permissions to access it.has_permission
to determine if a user is authorized to perform an action.PermissionRequiredMixin
mixinPermissionRequiredMixin
is a mixin for class-based views in Django that allows you to restrict access to views based on specific permissions. It can be used to require users to have certain permissions before accessing a particular view.
Here's how you can use the PermissionRequiredMixin in your Django project:
from django.views.generic import TemplateView
from django.contrib.auth.mixins import PermissionRequiredMixin
from web_project import TemplateLayout
PermissionRequiredMixin
:class AccessView(PermissionRequiredMixin, TemplateView):
permission_required
attribute as a tuple of permission strings that the user must have: permission_required = (
"permission.view_permission",
"permission.delete_permission",
"permission.change_permission",
"permission.add_permission",
)
In this example, the view requires the user to have the following permissions: view_permission, delete_permission, change_permission, and add_permission
. Users must have all of these permissions to access the view.
By using the PermissionRequiredMixin
with the permission_required attribute, you can restrict access to the AccessView
based on the specified permissions. Users must have all the required permissions to access this view.
Example usage:
from django.views.generic import TemplateView
from web_project import TemplateLayout
from django.contrib.auth.mixins import PermissionRequiredMixin
"""
This file is a view controller for multiple pages as a module.
Here you can override the page view layout.
Refer to access/urls.py file for more pages."""
class AccessView(PermissionRequiredMixin, TemplateView):
permission_required = ("permission.view_permission", "permission.delete_permission", "permission.change_permission", "permission.add_permission")
# Predefined function
def get_context_data(self, **kwargs):
# A function to init the global layout. It is defined in web_project/__init__.py file
context = TemplateLayout.init(self, super().get_context_data(**kwargs))
return context
permission_required
decoratorpermission_required
. We're using class-based views in Materialize, so we will be using PermissionRequiredMixin
.
The @permission_required
decorator in Django is a powerful tool for restricting access to views based on user permissions. It ensures that only users with specific permissions are allowed to access a particular view. This guide will walk you through the usage of the @permission_required
decorator with example code.
Prerequisites:
models.py
file using the Permission model.Decorator Usage
To use the @permission_required
decorator, follow these steps:
from django.contrib.auth.decorators import permission_required
@permission_required('app_label.codename', login_url=None, raise_exception=False)
app_label
is the label of the application where the permission is defined.codename
is the codename of the permission you want to check.login_url
(optional, we're using LOGIN_URL option in setting.py
to set it.) is the URL to redirect to if the user doesn't have the required permission. If set to None, the user will see a "Permission Denied" message.raise_exception
(optional) is a boolean that determines whether a PermissionDenied exception should be raised if the user lacks the required permission. If set to True, an exception will be raised; if set to False, the user will be redirected to the login URL.example usage
from django.views.generic import TemplateView
from web_project import TemplateLayout
from django.contrib.auth.decorators import permission_required
class MyRestrictedView(TemplateView):
"""
A view that requires specific permissions to access.
"""
# Apply the @permission_required decorator with the required permissions.
@permission_required("myapp.can_access_view", login_url='/login/', raise_exception=False)
def get(self, request, *args, **kwargs):
# Your view logic here
context = TemplateLayout.init(self, super().get_context_data(**kwargs))
return context
In this example, the MyRestrictedView
class uses the @permission_required
decorator to require the can_access_view
permission from our application. If a user doesn't have this permission, they will be redirected to the /login/
URL. You can customize the behavior by adjusting the login_url
and raise_exception
parameters.
By following these steps, you can easily control access to views based on user permissions in your Django project. For more details refer: The permission_required decorator
{{ perms }}
PermissionsThe currently logged-in user’s permissions are stored in the template variable .This is an instance of
django.contrib.auth.context_processors.PermWrapper
, which is a template-friendly proxy of permissions. For more details refer Permission
{% if perms.foo %}
{% if perms.foo.add_vote %}
Example usage:
In Materialize's Transaction app, you can secure the transactions_list.html
view using Django's built-in permissions and roles. This ensures that only users with the appropriate permissions can access this view.
add_transaction, view_transaction, edit_transaction and update_transaction
.view_transaction
.
{% if perms.transactions.view_transaction %}
<div class="row g-4 mb-6">
<div class="col-sm-6 col-xl-3">
<div class="card">
<div class="card-body">
<div class="d-flex align-items-start justify-content-between">
<div class="content-left">
<div class="d-flex align-items-end">
<h3 class="mb-0 me-2">{{ transactions_count }}</h3>
<small class="text-primary"></small>
</div>
<small>Total Transactions</small>
</div>
<span class="badge bg-label-primary rounded p-2">
<i class="ri-exchange-funds-line ri-24px"></i>
</span>
</div>
</div>
</div>
</div>
<div class="col-sm-6 col-xl-3">
<div class="card">
<div class="card-body">
<div class="d-flex align-items-start justify-content-between">
<div class="content-left">
<div class="d-flex align-items-end">
<h3 class="mb-0 me-2">$ {{ paid_count }}</h3>
<small class="text-primary"></small>
</div>
<small>Total Paid</small>
</div>
<span class="badge bg-label-success rounded p-2">
<i class="ri-check-fill ri-24px"></i>
</span>
</div>
</div>
</div>
</div>
<div class="col-sm-6 col-xl-3">
<div class="card">
<div class="card-body">
<div class="d-flex align-items-start justify-content-between">
<div class="content-left">
<div class="d-flex align-items-end">
<h3 class="mb-0 me-2">$ {{ due_count }}</h3>
<small class="text-primary"></small>
</div>
<small>Total Due</small>
</div>
<span class="badge bg-label-warning rounded p-2">
<i class="ri-timer-flash-line ri-24px"></i>
</span>
</div>
</div>
</div>
</div>
<div class="col-sm-6 col-xl-3">
<div class="card">
<div class="card-body">
<div class="d-flex align-items-start justify-content-between">
<div class="content-left">
<div class="d-flex align-items-end">
<h3 class="mb-0 me-2">$ {{ canceled_count }}</h3>
<small class="text-primary"></small>
</div>
<small>Total Canceled</small>
</div>
<span class="badge bg-label-danger rounded p-2">
<i class="ri-forbid-line ri-24px"></i>
</span>
</div>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-datatable table-responsive">
<table class="datatables-transaction table">
<thead class="table-light">
<tr class="text-nowrap">
<th></th>
<th>Id</th>
<th>Customer</th>
<th>Transaction Date</th>
<th>Due Date</th>
<th>Total</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for transaction in transactions %}
<tr>
<td></td>
<td>{{ transaction.id }}</td>
<td class="text-nowrap fw-medium text-heading">{{ transaction.customer|capfirst }}</td>
<td class="text-nowrap">{{ transaction.transaction_date }}</td>
<td class="text-nowrap">{{ transaction.due_date }}</td>
<td class="text-nowrap">$ {{ transaction.total }}</td>
<td>
<div class="badge bg-label-{% if transaction.status == 'Paid' %}success{% elif transaction.status == 'Due' %}warning{% elif transaction.status == 'Canceled' %}danger{% endif %} rounded-pill">
{{transaction.status}}
</div>
</td>
<td>
<div class="d-inline-block text-nowrap">
<!-- permission required: edit_transaction -->
{% if perms.transactions.edit_transaction %}
<a href="{% url 'transactions-update' transaction.id %}" class="btn btn-sm btn-icon btn-text-secondary rounded-pill waves-effect"><i class='ri-edit-box-line ri-22px'></i></a>
{% endif %}
<!-- permission required: delete_transaction -->
{% if perms.transactions.delete_transaction %}
<a href="{% url 'transactions-delete' transaction.id %}" class="btn btn-sm btn-icon btn-text-secondary rounded-pill waves-effect delete-transaction" data-transaction-username="{{ transaction.customer|capfirst }}"><i class="ri-delete-bin-7-line ri-22px"></i></a>
{% endif %}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
Materialize provides built-in functionality to display menu-header, menu-tem and menu-group according to user/group permission.
vertical_menu.json
and horizontal_menu.json
file.
permission
attribute in a menu JSON to show menu headers, items, and groups based on user or group permissions. However, it won't provide protection for viewing or accessing URLs. If you want to control access to views based on permissions, you should use The PermissionRequiredMixin
mixin.
Result: User with view_transaction
permission can view this menu-header.
...
{
"menu_header": "Apps & Pages"
"permission": "transactions.view_transaction",
},
...
Result: Admin and Client user has permission view_transaction
, so they can view this menu-item.
...
{
"url": "transactions",
"name": "Transactions (CRUD)",
"permission": "transactions.view_transaction",
"icon": "menu-icon tf-icons ri-database-2-line",
"slug": "transactions"
},
...
Result: Admin user has permission view_permission
, so they can view this menu-group.
...
{
"name": "Roles & Permissions",
"icon": "menu-icon tf-icons ri-lock-2-line",
"permission": "permission.view_permission",
"slug": "app-access",
"submenu": [
{
"url": "app-access-roles",
"name": "Roles",
"slug": "app-access-roles"
},
{
"url": "app-access-permission",
"name": "Permissions",
"slug": "app-access-permission"
}
]
},
...