Django backoffice config

Version 10 (Paul Carensac, 03/29/2016 11:59 am)

1 2 Etienne Pallier
h1. CONFIGURATION of the Django Back Office (administration interface)
2 1 Etienne Pallier
3 1 Etienne Pallier
4 3 Etienne Pallier
{{>toc}}
5 3 Etienne Pallier
6 3 Etienne Pallier
7 1 Etienne Pallier
---
8 1 Etienne Pallier
9 1 Etienne Pallier
h3. Back Office setup
10 1 Etienne Pallier
11 1 Etienne Pallier
 * Prerequisites in src/pyros/settings.py :
12 1 Etienne Pallier
13 1 Etienne Pallier
    * INSTALLED_APPS must (at least) contain :
14 1 Etienne Pallier
15 1 Etienne Pallier
        * django.contrib.admin
16 1 Etienne Pallier
        * django.contrib.auth
17 1 Etienne Pallier
        * django.contrib.contenttypes
18 1 Etienne Pallier
        * django.contrib.sessions
19 1 Etienne Pallier
20 4 Etienne Pallier
    * MIDDLEWARE_CLASSES must (at least) contain :
21 1 Etienne Pallier
22 1 Etienne Pallier
        * django.contrib.sessions.middleware.SessionMiddleware
23 1 Etienne Pallier
        * django.middleware.common.CommonMiddleware
24 1 Etienne Pallier
        * django.contrib.auth.middleware.AuthenticationMiddleware
25 1 Etienne Pallier
26 1 Etienne Pallier
 * At least one 'python manage.py migrate' must have been executed
27 1 Etienne Pallier
28 1 Etienne Pallier
 * Create a superuser for the administration :
29 1 Etienne Pallier
30 1 Etienne Pallier
<pre>
31 1 Etienne Pallier
$ python manage.py createsuperuser
32 1 Etienne Pallier
</pre>
33 1 Etienne Pallier
34 1 Etienne Pallier
* For each app of the project, fill the admin.py file :
35 1 Etienne Pallier
36 1 Etienne Pallier
<pre>
37 1 Etienne Pallier
from django.contrib import admin
38 5 Etienne Pallier
from app.models import Model1, Model2, ..., ModelN
39 5 Etienne Pallier
(or "from app.models import *")
40 1 Etienne Pallier
41 1 Etienne Pallier
admin.site.register(Model1)
42 1 Etienne Pallier
admin.site.register(Model2)
43 5 Etienne Pallier
...
44 5 Etienne Pallier
admin.site.register(ModelN)
45 1 Etienne Pallier
</pre>
46 5 Etienne Pallier
47 5 Etienne Pallier
So, for our application "pyrosapp", we have:
48 5 Etienne Pallier
<pre>
49 5 Etienne Pallier
from pyrosapp.models import *
50 5 Etienne Pallier
...
51 5 Etienne Pallier
</pre>
52 5 Etienne Pallier
53 1 Etienne Pallier
54 1 Etienne Pallier
*Reminder* : each application must be registered in the settings.py INSTALLED_APPS variable.
55 1 Etienne Pallier
56 1 Etienne Pallier
* For each model in models.py, add a '__str__()' method in order to identify the object on the back office. Example :
57 1 Etienne Pallier
58 1 Etienne Pallier
<pre>
59 1 Etienne Pallier
class UserLevel(models.Model):
60 1 Etienne Pallier
    name = models.CharField(max_length=45, blank=True, null=True)
61 1 Etienne Pallier
    desc = models.TextField(blank=True, null=True)
62 1 Etienne Pallier
    priority = models.IntegerField(blank=True, null=True)
63 1 Etienne Pallier
    quota = models.FloatField(blank=True, null=True)
64 1 Etienne Pallier
65 1 Etienne Pallier
    class Meta:
66 1 Etienne Pallier
        managed = True
67 1 Etienne Pallier
        db_table = 'userlevel'
68 1 Etienne Pallier
69 1 Etienne Pallier
    def __str__(self):
70 1 Etienne Pallier
        return (str(self.name))
71 1 Etienne Pallier
</pre>
72 1 Etienne Pallier
73 1 Etienne Pallier
*Naming convention* : Use self.name when possible, the creation time/date otherwise. Example :
74 1 Etienne Pallier
75 1 Etienne Pallier
<pre>
76 1 Etienne Pallier
class SiteWatch(models.Model):
77 1 Etienne Pallier
    updated = models.DateTimeField(blank=True, null=True)
78 1 Etienne Pallier
    lights = models.CharField(max_length=45, blank=True, null=True)
79 1 Etienne Pallier
    dome = models.CharField(max_length=45, blank=True, null=True)
80 1 Etienne Pallier
    doors = models.CharField(max_length=45, blank=True, null=True)
81 1 Etienne Pallier
    temperature = models.FloatField(blank=True, null=True)
82 1 Etienne Pallier
83 1 Etienne Pallier
    class Meta:
84 1 Etienne Pallier
        managed = True
85 1 Etienne Pallier
        db_table = 'sitewatch'
86 1 Etienne Pallier
87 1 Etienne Pallier
    def __str__(self):
88 1 Etienne Pallier
        return (str(self.updated))
89 1 Etienne Pallier
</pre>
90 1 Etienne Pallier
91 1 Etienne Pallier
---
92 1 Etienne Pallier
93 1 Etienne Pallier
h3. Adaptation of the one-to-many and many-to-many display
94 1 Etienne Pallier
95 7 Etienne Pallier
*1) The one-to-many relationships*
96 1 Etienne Pallier
97 9 Etienne Pallier
* The one-to-many relationships are the following (One.many format) :
98 7 Etienne Pallier
99 1 Etienne Pallier
    * Schedule.sequences
100 1 Etienne Pallier
    * Request.sequences
101 1 Etienne Pallier
    * Sequence.albums
102 1 Etienne Pallier
    * Album.plans
103 1 Etienne Pallier
    * Plan.images
104 1 Etienne Pallier
    * Telescope.detectors
105 1 Etienne Pallier
    * Detector.filters
106 1 Etienne Pallier
    * NrtAnalysis.images
107 1 Etienne Pallier
    * Filter.plans
108 1 Etienne Pallier
    * Detector.albums
109 1 Etienne Pallier
    * UserLevel.users
110 1 Etienne Pallier
    * Country.users
111 1 Etienne Pallier
    * ScientificProgram.requests
112 1 Etienne Pallier
    * User.requests
113 1 Etienne Pallier
    * StrategyObs.alerts
114 1 Etienne Pallier
    * SequenceType.sequences
115 1 Etienne Pallier
116 6 Etienne Pallier
* For each "many", create a new class in admin.py just after the imports, following these examples :
117 6 Etienne Pallier
118 1 Etienne Pallier
<pre>
119 1 Etienne Pallier
120 1 Etienne Pallier
For Schedule.sequences, Request.sequences and Sequentype.sequences, we will need :
121 1 Etienne Pallier
122 1 Etienne Pallier
class SequenceInline(admin.TabularInline):
123 1 Etienne Pallier
    model = Sequence
124 10 Paul Carensac
    readonly_fields = ("name",)
125 1 Etienne Pallier
    fields = ("name",)
126 1 Etienne Pallier
    show_change_link = True
127 1 Etienne Pallier
128 1 Etienne Pallier
129 1 Etienne Pallier
For Sequence.albums and Detector.albums, we will need :
130 1 Etienne Pallier
131 1 Etienne Pallier
class AlbumInline(admin.TabularInline):
132 1 Etienne Pallier
    model = Album
133 10 Paul Carensac
    readonly_fields = ("name",)
134 1 Etienne Pallier
    fields = ("name",)
135 1 Etienne Pallier
    show_change_link = True
136 1 Etienne Pallier
137 1 Etienne Pallier
138 1 Etienne Pallier
For StrategyObs.alerts, we will need :
139 1 Etienne Pallier
140 1 Etienne Pallier
class AlertInline(admin.TabularInline):
141 1 Etienne Pallier
    model = Alert
142 10 Paul Carensac
    readonly_fields = ("request_name",) # there is no 'name' attribute in the Alert model, so we use a custom method
143 10 Paul Carensac
    fields = ("request_name",)
144 1 Etienne Pallier
    show_change_link = True
145 1 Etienne Pallier
146 1 Etienne Pallier
</pre>
147 1 Etienne Pallier
148 1 Etienne Pallier
* For each "One", declare a new class in admin.py, just after the "Inlines" class declaration, as done in the following examples :
149 1 Etienne Pallier
150 1 Etienne Pallier
<pre>
151 1 Etienne Pallier
For Request.sequences :
152 1 Etienne Pallier
153 1 Etienne Pallier
class RequestAdmin(admin.ModelAdmin):
154 1 Etienne Pallier
    inlines = [
155 1 Etienne Pallier
	SequenceInline,
156 1 Etienne Pallier
    ]
157 1 Etienne Pallier
158 1 Etienne Pallier
For Detector.filters and Detector.albums :
159 1 Etienne Pallier
160 1 Etienne Pallier
class DetectorAdmin(admin.ModelAdmin):
161 1 Etienne Pallier
    inlines = [
162 8 Etienne Pallier
        FilterInline,
163 1 Etienne Pallier
        AlbumInline,
164 1 Etienne Pallier
    ]
165 1 Etienne Pallier
166 1 Etienne Pallier
</pre>
167 1 Etienne Pallier
168 1 Etienne Pallier
169 7 Etienne Pallier
*2) The many-to-many relationships*
170 7 Etienne Pallier
171 9 Etienne Pallier
* The many-to-many relationships are the following :
172 1 Etienne Pallier
173 1 Etienne Pallier
    * ScientificProgram - User
174 1 Etienne Pallier
    * ScheduleHistory - Sequence
175 1 Etienne Pallier
176 1 Etienne Pallier
* For each many-to-many relationship, declare a new "Inline" class in admin.py just after the imports, like this :
177 1 Etienne Pallier
178 1 Etienne Pallier
<pre>
179 1 Etienne Pallier
For ScientificProgram - User :
180 1 Etienne Pallier
181 1 Etienne Pallier
class UserAndSPInline(admin.TabularInline):
182 1 Etienne Pallier
    model = ScientificProgram.users.through
183 1 Etienne Pallier
184 1 Etienne Pallier
185 1 Etienne Pallier
For ScheduleHistory - Sequence
186 1 Etienne Pallier
187 1 Etienne Pallier
class SequenceAndSHInline(admin.TabularInline):
188 1 Etienne Pallier
    model = ScheduleHistory.sequences.through
189 1 Etienne Pallier
190 1 Etienne Pallier
</pre>
191 1 Etienne Pallier
192 1 Etienne Pallier
+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.
193 1 Etienne Pallier
194 1 Etienne Pallier
* For each many-to-many relationship, declare two new classes in admin.py, just after the inlines, like in the following examples :
195 1 Etienne Pallier
196 1 Etienne Pallier
<pre>
197 1 Etienne Pallier
For the ScheduleHistory - Sequence relationship :
198 1 Etienne Pallier
199 1 Etienne Pallier
class ScheduleHistoryAdmin(admin.ModelAdmin):
200 1 Etienne Pallier
    inlines = [
201 1 Etienne Pallier
        SequenceAndSHInline,
202 1 Etienne Pallier
    ]
203 1 Etienne Pallier
    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
204 1 Etienne Pallier
205 1 Etienne Pallier
class SequenceAdmin(admin.ModelAdmin):
206 1 Etienne Pallier
    inlines = [
207 1 Etienne Pallier
        AlbumInline,        # This is the Inline for the one-to-many relationship Sequence.albums
208 1 Etienne Pallier
        SequenceAndSHInline,                                                                
209 1 Etienne Pallier
    ]
210 1 Etienne Pallier
211 1 Etienne Pallier
For the ScientificProgram - User relationship :
212 1 Etienne Pallier
213 1 Etienne Pallier
class ScientificProgramAdmin(admin.ModelAdmin):
214 1 Etienne Pallier
    inlines = [
215 1 Etienne Pallier
        RequestInline,
216 1 Etienne Pallier
	UserAndSPInline,                                                                         
217 1 Etienne Pallier
    ]
218 1 Etienne Pallier
    exclude = ('users',) # Same as ScheduleHistory                                                                         
219 1 Etienne Pallier
220 1 Etienne Pallier
class UserAdmin(admin.ModelAdmin):
221 1 Etienne Pallier
    inlines = [
222 1 Etienne Pallier
	RequestInline,   # This is the Inline for the one-to-many relationship User.requests
223 1 Etienne Pallier
        UserAndSPInline,                                                                    
224 1 Etienne Pallier
    ]
225 1 Etienne Pallier
226 1 Etienne Pallier
</pre>
227 1 Etienne Pallier
228 1 Etienne Pallier
* For each ModelAdmin class in the admin.py, change the registering line
229 1 Etienne Pallier
230 1 Etienne Pallier
<pre>
231 1 Etienne Pallier
admin.site.register(Album)
232 1 Etienne Pallier
</pre>
233 1 Etienne Pallier
234 1 Etienne Pallier
to
235 1 Etienne Pallier
236 1 Etienne Pallier
<pre>
237 1 Etienne Pallier
admin.site.register(Album, AlbumAdmin)
238 1 Etienne Pallier
</pre>