Overview

Django 2.1, released on August 1, 2018, delivers a highly requested improvement: the view permission on models. Until now, the admin interface only offered add, change, and delete permissions. It is now possible to grant a user read-only access. This release also introduces test database reuse between runs.

Key Features

Model 'view' permission

Every model now has four default permissions: add, change, delete, and view. The view permission allows viewing an object in the admin without being able to modify it. This is especially useful for dashboards and supervisory roles.

python
from django.contrib.auth.models import User, Permission
from django.contrib.contenttypes.models import ContentType

# Retrieve the 'view' permission for the Order model
ct = ContentType.objects.get_for_model(Order)
view_permission = Permission.objects.get(
    codename='view_order',
    content_type=ct,
)

# Assign the permission to a supervisor user
supervisor = User.objects.get(username='supervisor')
supervisor.user_permissions.add(view_permission)

# Check in a view
def dashboard(request):
    if request.user.has_perm('shop.view_order'):
        orders = Order.objects.all()
        return render(request, 'dashboard.html', {
            'orders': orders,
        })
    return HttpResponseForbidden('Access denied')

# In the admin, a read-only ModelAdmin
from django.contrib import admin

class OrderAdmin(admin.ModelAdmin):
    def has_change_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

Test database reuse

The test runner can now reuse the existing test database instead of recreating it on every run. The --keepdb option preserves the database between executions, which considerably speeds up development cycles on projects with many migrations.

python
# Run tests while keeping the database
# python manage.py test --keepdb

# The first run creates the database and applies migrations
# Subsequent runs reuse the existing database
# If the schema has changed, Django detects it and recreates the db

# Typical gain on a project with 200+ migrations:
# Without --keepdb: 45 seconds startup
# With --keepdb:     3 seconds startup

# Combine with --parallel for even more speed
# python manage.py test --keepdb --parallel

Sources