Django Object Level Permission Template
A template to guide you how to setup a Django Project with Object Level Permission.
1. Authentication
1.1. Packages
Djoser provide commonly use authentication functions such as: Sign Up, Login, Change Password, Forgot Password, User Account Activation, User Profile
Simple JWT provide Json Web Token authentication method.
Django Guardian provide object level permission management.
1.2. Configuration
- JWT authentication is configured in
core/settings.py
# Application definition
INSTALLED_APPS = [
(...),
'rest_framework',
'djoser',
'guardian',
]
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend', # default
'guardian.backends.ObjectPermissionBackend',
)
# Configuration for Django Rest Framework
# https://www.django-rest-framework.org/
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
# Simple JWT Authentication
# https://django-rest-framework-simplejwt.readthedocs.io/
'rest_framework_simplejwt.authentication.JWTAuthentication',
)
}
core/urls.py
urlpatterns = [
(...),
path('auth/', include('djoser.urls')),
path('auth/', include('djoser.urls.jwt')),
]
1.3. Data Model
1.3.1. Using a custom model
If you’re starting a new project, it’s highly recommended to set up a custom user model, even if the default User model is sufficient for you. This model behaves identically to the default user model, but you’ll be able to customize it in the future if the need arises.
core/user/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
pass
core/settings.py
AUTH_USER_MODEL = 'user.User'
INSTALLED_APPS = [
(...),
'core.user',
]
1.3.2. Reusable apps and AUTH_USER_MODEL
Reusable apps shouldn’t implement a custom user model. A project may use many apps, and two reusable apps that implemented a custom user model couldn’t be used together. If you need to store per user information in your app, use a ForeignKey
or OneToOneField
to settings.AUTH_USER_MODEL
as described below.
Referencing the User model
If you reference User
directly (for example, by referring to it in a foreign key), your code will not work in projects where the AUTH_USER_MODEL
setting has been changed to a different user model.
Instead of referring to User directly, you should reference the user model using django.contrib.auth.get_user_model()
. This method will return the currently active user model – the custom user model if one is specified, or User otherwise.
When you define a foreign key
or many-to-many
relations to the user model, you should specify the custom model using the AUTH_USER_MODEL
setting. For example:
from django.conf import settings |
1.4. Declare model permissions
1.4.1 Django builtin permission
Django comes with a built-in permissions system. It provides a way to assign permissions to specific users and groups of users.
When django.contrib.auth
is listed in your INSTALLED_APPS setting, it will ensure that four default permissions – add
, change
, delete
, and view
– are created for each Django model defined in one of your installed applications.
1.4.2 Declare new permission
Define directly inside model class Job(models.Model):
(...)
class Meta:
permissions = [('review_job', 'Can review job (approve or deny)')]
from myapp.models import Job |
1.4.3 Assign permission to user/group
Global Permission >> from django.contrib.auth import get_user_model
>> from django.contrib.auth.models import Group
>> User = get_user_model()
>> jack = User.objects.create_user('jack', 'jack@example.com', 'topsecretagentjack')
>> jack.has_perm('auth.change_group')
False
>> from guardian.shortcuts import assign_perm
>> assign_perm('auth.change_group', jack)
>> jack.has_perm('auth.change_group')
True
Object Permission >> from django.contrib.auth import get_user_model
>> from django.contrib.auth.models import Group
>> User = get_user_model()
>> jack = User.objects.create_user('jack', 'jack@example.com', 'topsecretagentjack')
>> admins = Group.objects.create(name='admins')
>> jack.has_perm('auth.change_group', admins)
False
>> from guardian.shortcuts import assign_perm
>> assign_perm('auth.change_group', jack, admins)
>> jack.has_perm('auth.change_group', admins)
True
1.4.4 Retrieve user permitted objects
>> from django.contrib.auth import get_user_model |
2. Database
2.1. Packages
- dj-database-url database connection string parser that is helpful to parse database configuration in a connection string style.
2.2. Supported URL connection schema
Engine | Django Backend | URL |
---|---|---|
SQLite | django.db.backends.sqlite3 |
sqlite:///PATH |
PostgreSQL | django.db.backends.postgresql |
postgres://USER:PASSWORD@HOST:PORT/NAME |
PostGIS | django.contrib.gis.db.backends.postgis |
postgis://USER:PASSWORD@HOST:PORT/NAME |
MSSQL | sql_server.pyodbc |
mssql://USER:PASSWORD@HOST:PORT/NAME |
MySQL | django.db.backends.mysql |
mysql://USER:PASSWORD@HOST:PORT/NAME |
MySQL (GIS) | django.contrib.gis.db.backends.mysql |
mysqlgis://USER:PASSWORD@HOST:PORT/NAME |
Oracle | django.db.backends.oracle |
oracle://USER:PASSWORD@HOST:PORT/NAME |
Oracle (GIS) | django.contrib.gis.db.backends.oracle |
oraclegis://USER:PASSWORD@HOST:PORT/NAME |
Redshift | django_redshift_backend |
redshift://USER:PASSWORD@HOST:PORT/NAME |
SpatiaLite | django.contrib.gis.db.backends.spatialite |
spatialite:///PATH |
2.3. Configuration
This is configuration for the database, the default database will use sqlite3 for simple to quick to run in development mode. This may conflict with database you run on production mode because some of the funtion sqlite may not support. It is recommended to config the database in development mode have the same database system you run on production. To change the database system, config the environment variable DATABASE_URL
core/settings.py
import dj_database_url
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASE_URL = os.environ.get('DATABASE_URL', 'sqlite:///{}'.format(os.path.join(BASE_DIR, 'db.sqlite3')))
DATABASES = {
'default': dj_database_url.config(default=DATABASE_URL)
}
3. API Development
3.1. Packages
- djangorestframework-jsonapi provide the implementation of the JSON API format specification
3.2. Serializers
TODO What is serializers, how to code one?
3.3. Views
TODO What is views, how to code one?