DEV Community

Varun Krishnan
Varun Krishnan

Posted on Originally published at dbdiagramr.space AI-assisted

Django Auth Tables and Permissions Explained

DJANGO AUTH Schema Diagram built on DBDiagramr

Django creates 5 core auth tables: auth_user, auth_group, auth_permission, django_content_type, and two join tables (auth_user_groups, auth_group_permissions). The permission system is built on content types each model gets a default add, change, delete, and view permission, and you can create custom ones.

The core tables

auth_user

Column Type What it means
id int (PK) Auto-incrementing primary key.
password varchar(128) Hashed password (PBKDF2 by default).
last_login datetime When the user last logged in. Null if never.
is_superuser bool Bypasses all permission checks.
username varchar(150) Unique username.
first_name varchar(150) User's first name.
last_name varchar(150) User's last name.
email varchar(254) Email address. Not necessarily unique.
is_staff bool Can access the Django admin.
is_active bool Set to False instead of deleting users.
date_joined datetime Registration time.

auth_group

Column Type What it means
id int (PK) Auto-incrementing ID.
name varchar(150) Unique group name (e.g., "Editors", "Moderators").

Groups are role containers. Assign permissions to groups, then add users to groups.

auth_permission

Column Type What it means
id int (PK) Auto-incrementing ID.
name varchar(255) Human-readable name (e.g., "Can add post").
content_type_id int (FK) Which model this permission applies to.
codename varchar(100) Code identifier (e.g., add_post).

Each model gets 4 default permissions: add_modelname, change_modelname, delete_modelname, view_modelname.

django_content_type

Column Type What it means
id int (PK) Auto-incrementing ID.
app_label varchar(100) The Django app (e.g., blog).
model varchar(100) The model name (e.g., post).

This table maps every model in your project to an ID. The permission system uses it to know which model a permission applies to.

auth_user_groups

Join table for many-to-many: users ↔ groups.

Column Type What it means
id int (PK) Auto-incrementing ID.
user_id int (FK) auth_user.id.
group_id int (FK) auth_group.id.

auth_group_permissions

Join table for many-to-many: groups ↔ permissions.

Column Type What it means
id int (PK) Auto-incrementing ID.
group_id int (FK) auth_group.id.
permission_id int (FK) auth_permission.id.

How permissions work

User ──M──M── Group ──M──M── Permission ──M──1── ContentType
Enter fullscreen mode Exit fullscreen mode
  1. A permission is tied to a content type (a specific model).
  2. Groups collect permissions (e.g., "Editors" get add_post, change_post).
  3. Users are added to groups to inherit their permissions.
  4. You can also assign permissions directly to users (bypass groups).

In code:

# Check permission
user.has_perm('blog.add_post')

# Add user to group
from django.contrib.auth.models import Group
editors = Group.objects.get(name='Editors')
user.groups.add(editors)

# Create custom permission
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from blog.models import Post
content_type = ContentType.objects.get_for_model(Post)
custom_perm = Permission.objects.create(
    codename='publish_post',
    name='Can publish post',
    content_type=content_type,
)
Enter fullscreen mode Exit fullscreen mode

What to change

  • Add a role field to auth_user if you need simple role-based access (or use groups).
  • Add an avatar field for profile pictures.
  • Create custom permissions for fine-grained access control (e.g., publish_post, archive_post).
  • Add unique=True to email if you want unique emails.

What to leave alone

  • Don't modify django_content_type it's managed by Django's migration framework.
  • Don't change auth_permission.codename it's referenced by has_perm() and decorators.
  • Don't delete auth_user.is_active use it instead of deleting users (preserves foreign keys).

FAQ

Does Django create all these tables automatically?

Yes. Running python manage.py migrate creates all auth tables. They're part of Django's built-in django.contrib.auth app.

Can I use Django without the permission system?

Yes. Remove django.contrib.auth from INSTALLED_APPS and you lose the permission tables but keep the auth_user model (or replace it entirely).

What's the difference between is_superuser and is_staff?

is_superuser bypasses all permission checks. is_staff only controls access to the Django admin. A superuser automatically has is_staff=True.

How do I see my Django auth tables?

Use dbdiagramr paste your connection string and get a visual schema of your Django auth tables.

Top comments (0)