14. Admin panel

14.1. Customizong

from django.contrib import admin
from django.utils.translation import ugettext_lazy as _

admin.site.site_header = _('HabitatOS')
admin.site.index_title = _('Dashboard')
admin.site.site_title = _('HabitatOS')

14.2. Permissions

14.2.1. Users

14.2.2. Groups

14.2.3. Content Types

14.3. Model Admin

  • admin.ModelAdmin

14.3.1. Model registering

  • @admin.register(...)

14.3.2. Admin fields

  • readonly_fields
  • search (^, =, @)
  • ordering
  • list_filter

14.3.3. Writing own list_filter

Code Listing 14.1. Writing own list_filter
from django.contrib import admin
from django.utils.translation import ugettext_lazy as _


class AgeFilter(admin.SimpleListFilter):
    # Human-readable title which will be displayed in the
    # right admin sidebar just above the filter options.
    title = _('Age')

    # Parameter for the filter that will be used in the URL query.
    parameter_name = 'age'

    def lookups(self, request, model_admin):
        return [
            ('None', _('Not Specified')),
            ('0-10', _('0-10')),
            ('11-20', _('11-20')),
            ('21-30', _('21-30')),
            ('31-40', _('31-40')),
            ('41-50', _('41-50')),
            ('51-60', _('51-60')),
            ('Older', _('Older')),
        ]

    def queryset(self, request, queryset):
        if self.value() == 'None':
            return queryset.filter(date_of_birth=None)

14.4. Model Inlines

14.4.1. StackedInline

14.4.2. TabularInline

14.5. Extending Admin

14.5.1. Media Class

class Media:
    js = [
        'communication/js/email-reply-button.js',
        'communication/js/email-hide-save.js',
    ]
    css = {'all': [
        'communication/css/hide-id-field.css',
        'communication/css/resize-fields.css',
    ]}

14.6. ModelAdmin Example

Code Listing 14.2. ModelAdmin Example
from django.contrib import admin
from django.utils.translation import ugettext_lazy as _


@admin.register(Contact)
class ContactAdmin(admin.ModelAdmin):
    list_display = ['last_name', 'first_name', 'date_of_birth', 'column_age']
    list_display_links = ['last_name']
    search_fields = ['^last_name']
    list_filter = ['created', 'modified', AgeFilter]
    inlines = [AddressInline]
    exclude = ['reporter', 'created', 'updated']
    readonly_fields = []
    ordering = ['last_name', 'first_name']
    autocomplete_fields = ['friends']
    fieldsets = [
        (_('Personal Data'), {'fields': ['last_name', 'first_name', 'date_of_birth', 'gender']}),
        (_('Additional Data'), {'fields': ['email', 'bio', 'image']}),
        (_('Relations'), {'fields': ['status', 'friends']})]
    radio_fields = {
        'gender': admin.HORIZONTAL,
        'status': admin.VERTICAL}
    # formfield_overrides = {models.ManyToManyField: {'widget': CheckboxSelectMultiple}}

    def get_list_display(self, request):
        list_display = super().get_list_display(request)

        if request.user.is_superuser and 'is_deleted' not in list_display:
            list_display += ['is_deleted']

        return list_display

    def get_queryset(self, request):
        queryset = super().get_queryset(request)

        if request.user.is_superuser:
            return queryset
        else:
            return queryset.filter(is_deleted=False)

    def column_age(self, obj):
        age = obj.get_age()
        return str(age) if age else ''

    # https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display
    column_age.short_description = _('Age')
    column_age.empty_value_display = ''
    column_age.admin_order_field = 'date_of_birth'

    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',
        ]}

14.7. django-import-export

$ pip install django-import-export
# settings.py
INSTALLED_APPS += ['import_export']
# <app>/admin.py
from import_export.admin import ImportExportModelAdmin

@admin.register(Command)
class CommandAdmin(ImportExportModelAdmin):
    pass

14.8. Grapelli

14.8.1. Installation

$ pip install django-grapelli
  • dodanie do INSTALLED_APPS
INSTALLED_APPS = [
    'grappelli.dashboard',
    'grappelli',
]
  • dodanie do urls
from django.conf.urls import url
from django.conf.urls import include
from django.contrib import admin


urlpatterns += [
    url(r'^grappelli/', include('grappelli.urls'), name='grappelli'),
    url(r'^', admin.site.urls, name='admin'),
]

14.8.2. Settings

GRAPPELLI_SWITCH_USER = True
GRAPPELLI_ADMIN_TITLE = _('HabitatOS')
GRAPPELLI_INDEX_DASHBOARD = 'habitat.dashboard.icares1.AdminDashboard'
GRAPPELLI_AUTOCOMPLETE_SEARCH_FIELDS = {
    'auth': {
        'user': ['username__icontains']
    }
}
from django.utils.translation import ugettext_lazy as _
from grappelli.dashboard import Dashboard
from grappelli.dashboard import modules


class AdminDashboard(Dashboard):

    def init_with_context(self, context):

        # Column 1
        self.children.append(modules.ModelList(
            title=_('Questionaries - Visible only to you'),
            column=1,
            collapsible=False,
            models=[
                'habitat.reporting.models.mood.Mood',
                'habitat.reporting.models.sociodynamics.SociodynamicReport',
                'habitat.reporting.models.sleep.Sleep']))

        self.children.append(modules.ModelList(
            title=_('Health - Visible only to you'),
            column=1,
            collapsible=False,
            models=[
                'habitat.health.models.blood_pressure.BloodPressure',
                'habitat.health.models.urine.Urine',
                'habitat.health.models.temperature.Temperature',
                'habitat.health.models.weight.Weight']))

        # Column 2
        self.children.append(modules.ModelList(
            title=_('Communication'),
            column=2,
            collapsible=False,
            models=[
                'habitat.communication.models.email.Email']))

        self.children.append(modules.ModelList(
            title=_('Reporting - Visible to anyone'),
            column=2,
            collapsible=False,
            models=[
                'habitat.reporting.models.daily.Daily',
                'habitat.reporting.models.repair.Repair',
                'habitat.reporting.models.incident.Incident',
                'habitat.reporting.models.waste.Waste',
                'habitat.communication.models.diary.DiaryEntry',
                'habitat.extravehicular.models.activity.Activity']))

        self.children.append(modules.ModelList(
            title=_('Water - Visible to anyone'),
            column=2,
            collapsible=False,
            models=[
                'habitat.water.models.technical.TechnicalWater',
                'habitat.water.models.drinking.DrinkingWater',
                'habitat.water.models.green.GreenWater']))

        # Column 3
        if context['user'].has_perm('admin.add_user'):
            self.children.append(modules.ModelList(
                title=_('Administration'),
                column=3,
                collapsible=True,
                models=['django.contrib.*'],
                css_classes=['grp-closed']))

        self.children.append(modules.LinkList(
            title=_('Shortcuts'),
            collapsible=False,
            column=3,
            children=[
                {'title': _('Schedule'), 'url': '/api/v1/dashboard/schedule/'},
                {'title': _('Martian Clock Converter'), 'url': '/api/v1/timezone/martian-standard-time/converter/'},
                {'title': _('Subjective Time Perception'), 'url': 'http://time.astrotech.io'},
            ]))

        self.children.append(modules.ModelList(
            title=_('Sensors'),
            column=3,
            collapsible=False,
            models=[
                'habitat.sensors.models.zwave_sensor.ZWaveSensor']))

14.8.3. Template overwrite

change_list_template = 'admin/change_list_import_export.html'
change_list_filter_template = 'admin/filter_listing.html'

14.8.4. Autocomplete

14.8.5. TinyMCE

14.8.6. FileUploader

14.8.7. list_editable

14.8.8. date_hierarchy