7.1. Admin About

7.1.1. Customizing

  • admin.site.site_title - browser tab title - default: "Django site admin"

  • admin.site.site_header - login box and dashboard (on the blueish background) - default: "Django Administration"

  • admin.site.index_title - app list index header (admin main page) - default: "Site administration"

>>> #
... from django.contrib import admin
... from django.utils.translation import gettext_lazy as _
...
... admin.site.site_title = _('My Administration')
... admin.site.site_header = _('My Project')
... admin.site.index_title = _('Dashboard')

7.1.2. ModelAdmin

  • admin.ModelAdmin

>>> #
... from django.contrib import admin
...
... class CustomerAdmin(admin.ModelAdmin):
...     pass

7.1.3. Registration

  • @admin.register(...)

>>> #
... from django.contrib import admin
... from shop.models import Customer
...
...
... @admin.register(Customer)
... class CustomerAdmin(admin.ModelAdmin):
...     pass

7.1.4. Example

>>> #
... from django.contrib import admin
... from django.utils.translation import gettext_lazy as _
...
...
... @admin.register(Customer)
... class CustomerAdmin(admin.ModelAdmin):
...     ordering = ['lastname', 'firstname']
...     list_display = ['lastname', 'firstname', 'birthdate', 'field_age']
...     list_display_links = ['lastname']
...     search_fields = ['^lastname']
...     list_filter = ['created_date', 'modified_date', 'gender']
...     exclude = ['uuid', 'reporter', 'is_active']
...     readonly_fields = ['created_date', 'modified_date']
...     autocomplete_fields = ['friends']
...     fieldsets = [
...         (_('Personal Data'), {'fields': ['lastname', 'firstname', 'birthdate', 'gender']}),
...         (_('Additional Data'), {'fields': ['email', 'bio', 'image']}),
...         (_('Relations'), {'fields': ['status', 'friends']})]
...     radio_fields = {
...         'gender': admin.HORIZONTAL,
...         'status': admin.VERTICAL}
...
...     def get_list_display(self, request):
...         list_display = super().get_list_display(request)
...         if request.user.is_superuser and 'is_active' not in list_display:
...             list_display.insert(0, 'is_active')
...         return list_display
...
...     def get_queryset(self, request):
...         queryset = super().get_queryset(request)
...         if not request.user.is_superuser:
...             queryset = queryset.filter(is_active=False)
...         return queryset
...
...     @admin.display(description=_('Age'), ordering='birthdate', empty_value=_('Unknown'))
...     def field_age(self, obj):
...         age = obj.get_age()
...         return str(age) if age else ''
...
...     def save_model(self, request, obj, form, change):
...         obj.reporter = request.user
...         super().save_model(request, obj, form, change)
...
...     class Media:
...         js = ['contact/js/alert.js']
...         css = {'all': ['contact/css/style.css']}

7.1.5. Permissions

7.1.6. Users

7.1.7. Groups

7.1.8. Content Types

7.1.9. Assignments

# doctest: +SKIP_FILE

# %% About
# - Name: Admin About ChangeTitles
# - Difficulty: easy
# - Lines: 1
# - Minutes: 2

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 0. Use `myproject.myapp`
# 1. Change the titles in admin panel:
#    - Site title: `My Project Admin`
#    - Site header: `My Project Administration`
#    - Index title: `Welcome to My Project Admin`

# %% Polish
# 0. Użyj `myproject.myapp`
# 1. Zmień tytuły w panelu admina:
#    - Tytuł strony: `My Project Admin`
#    - Nagłówek strony: `My Project Administration`
#    - Tytuł indeksu: `Welcome to My Project Admin`

# %% Hints
# - `admin.ModelAdmin`
# - `admin.site.site_title`
# - `admin.site.site_header`
# - `admin.site.index_title`

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0

>>> assert sys.version_info >= (3, 12), \
'Python has an is invalid version; expected: `3.12` or newer.'
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -f -v myfile.py`

# %% Imports
import os; os.environ['DJANGO_SETTINGS_MODULE'] = 'myproject.settings'
import django; django.setup()

# %% Types

# %% Data

# %% Result

# doctest: +SKIP_FILE

# %% About
# - Name: Admin About Register
# - Difficulty: easy
# - Lines: 1
# - Minutes: 2

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 0. Use `myproject.myapp`
# 1. Create admin class `BaseAdmin`
# 2. In `get_list_display()` add `is_deleted` field only for superusers
# 3. In `get_queryset()` filter out deleted objects for non-superusers
# 4. In `delete_model()` set `is_deleted` to `True` instead of deleting

# %% Polish
# 0. Użyj `myproject.myapp`
# 1. Stwórz klasę `BaseAdmin` admin
# 2. W `get_list_display()` dodaj pole `is_deleted` tylko dla superużytkowników
# 3. W `get_queryset()` odfiltruj usunięte obiekty dla nie-superużytkowników
# 4. W `delete_model()` ustaw `is_deleted` na `True` zamiast usuwania

# %% Hints
# - `admin.ModelAdmin`

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0

>>> assert sys.version_info >= (3, 12), \
'Python has an is invalid version; expected: `3.12` or newer.'
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -f -v myfile.py`

# %% Imports
import os; os.environ['DJANGO_SETTINGS_MODULE'] = 'myproject.settings'
import django; django.setup()
from django.contrib import admin

# %% Types

# %% Data

# %% Result

# doctest: +SKIP_FILE

# %% About
# - Name: Admin About Register
# - Difficulty: easy
# - Lines: 1
# - Minutes: 2

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 0. Use `myproject.myapp`
# 1. Create admin class for `myapp.Person` model
# 2. Register the admin class for the model

# %% Polish
# 0. Użyj `myproject.myapp`
# 1. Stwórz klasę admin dla modelu `myapp.Person`
# 2. Zarejestruj klasę admin dla modelu

# %% Hints
# - `admin.ModelAdmin`
# - `@admin.register(...)`

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0

>>> assert sys.version_info >= (3, 12), \
'Python has an is invalid version; expected: `3.12` or newer.'
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -f -v myfile.py`

# %% Imports
import os; os.environ['DJANGO_SETTINGS_MODULE'] = 'myproject.settings'
import django; django.setup()

# %% Types

# %% Data

# %% Result