CONFIGURATION of the Django Back Office (administration interface)


Back Office setup

  • Prerequisites in src/pyros/settings.py :
    • INSTALLED_APPS must (at least) contain :
      • django.contrib.admin
      • django.contrib.auth
      • django.contrib.contenttypes
      • django.contrib.sessions
    • MIDDLEWARE_CLASSES must (at least) contain :
      • django.contrib.sessions.middleware.SessionMiddleware
      • django.middleware.common.CommonMiddleware
      • django.contrib.auth.middleware.AuthenticationMiddleware
  • At least one 'python manage.py migrate' must have been executed
  • Create a superuser for the administration :
$ python manage.py createsuperuser
  • For each app of the project, fill the admin.py file :
from django.contrib import admin
from app.models import Model1, Model2, ..., ModelN
(or "from app.models import *")

admin.site.register(Model1)
admin.site.register(Model2)
...
admin.site.register(ModelN)

So, for our application "pyrosapp", we have:

from pyrosapp.models import *
...

Reminder : each application must be registered in the settings.py INSTALLED_APPS variable.

  • For each model in models.py, add a '__str__()' method in order to identify the object on the back office. Example :
class UserLevel(models.Model):
    name = models.CharField(max_length=45, blank=True, null=True)
    desc = models.TextField(blank=True, null=True)
    priority = models.IntegerField(blank=True, null=True)
    quota = models.FloatField(blank=True, null=True)

    class Meta:
        managed = True
        db_table = 'userlevel'

    def __str__(self):
        return (str(self.name))

Naming convention : Use self.name when possible, the creation time/date otherwise. Example :

class SiteWatch(models.Model):
    updated = models.DateTimeField(blank=True, null=True)
    lights = models.CharField(max_length=45, blank=True, null=True)
    dome = models.CharField(max_length=45, blank=True, null=True)
    doors = models.CharField(max_length=45, blank=True, null=True)
    temperature = models.FloatField(blank=True, null=True)

    class Meta:
        managed = True
        db_table = 'sitewatch'

    def __str__(self):
        return (str(self.updated))

Adaptation of the one-to-many and many-to-many display

1) The one-to-many relationships

  • The one-to-many relationships are the following (One.many format) :
    • Schedule.sequences
    • Request.sequences
    • Sequence.albums
    • Album.plans
    • Plan.images
    • Telescope.detectors
    • Detector.filters
    • NrtAnalysis.images
    • Filter.plans
    • Detector.albums
    • UserLevel.users
    • Country.users
    • ScientificProgram.requests
    • User.requests
    • StrategyObs.alerts
    • SequenceType.sequences
  • For each "many", create a new class in admin.py just after the imports, following these examples :

For Schedule.sequences, Request.sequences and Sequentype.sequences, we will need :

class SequenceInline(admin.TabularInline):
    model = Sequence
    readonly_fields = ("name",)
    fields = ("name",)
    show_change_link = True

For Sequence.albums and Detector.albums, we will need :

class AlbumInline(admin.TabularInline):
    model = Album
    readonly_fields = ("name",)
    fields = ("name",)
    show_change_link = True

For StrategyObs.alerts, we will need :

class AlertInline(admin.TabularInline):
    model = Alert
    readonly_fields = ("request_name",) # there is no 'name' attribute in the Alert model, so we use a custom method 'request_name' declared in the Alert model
    fields = ("request_name",)
    show_change_link = True

  • For each "One", declare a new class in admin.py, just after the "Inlines" class declaration, as done in the following examples :
For Request.sequences :

class RequestAdmin(admin.ModelAdmin):
    inlines = [
    SequenceInline,
    ]

For Detector.filters and Detector.albums :

class DetectorAdmin(admin.ModelAdmin):
    inlines = [
        FilterInline,
        AlbumInline,
    ]

2) The many-to-many relationships

  • The many-to-many relationships are the following :
    • ScientificProgram - User
    • ScheduleHistory - Sequence
  • For each many-to-many relationship, declare a new "Inline" class in admin.py just after the imports, like this :
For ScientificProgram - User :

class UserAndSPInline(admin.TabularInline):
    model = ScientificProgram.users.through

For ScheduleHistory - Sequence

class SequenceAndSHInline(admin.TabularInline):
    model = ScheduleHistory.sequences.through

Note : The order in the line "model = ScientificProgram.users.through" is very important : the first model (ScientificProgram) is the one in which is declared the ManyToManyField relationship.

  • For each many-to-many relationship, declare two new classes in admin.py, just after the inlines, like in the following examples :
For the ScheduleHistory - Sequence relationship :

class ScheduleHistoryAdmin(admin.ModelAdmin):
    inlines = [
        SequenceAndSHInline,
    ]
    exclude = ('sequences',) # ScheduleHistory declares the ManyToManyField, and we want to replace its display in the back office, so we won't display the default field

class SequenceAdmin(admin.ModelAdmin):
    inlines = [
        AlbumInline,        # This is the Inline for the one-to-many relationship Sequence.albums
        SequenceAndSHInline,                                                                
    ]

For the ScientificProgram - User relationship :

class ScientificProgramAdmin(admin.ModelAdmin):
    inlines = [
        RequestInline,
    UserAndSPInline,                                                                         
    ]
    exclude = ('users',) # Same as ScheduleHistory                                                                         

class UserAdmin(admin.ModelAdmin):
    inlines = [
    RequestInline,   # This is the Inline for the one-to-many relationship User.requests
        UserAndSPInline,                                                                    
    ]

  • For each ModelAdmin class in the admin.py, change the registering line
admin.site.register(Album)

to

admin.site.register(Album, AlbumAdmin)