Commit 6d86da1b2a438900f4f32729e6d804145057a60a

Authored by haribo
1 parent 0b51a2e3
Exists in master and in 1 other branch dev

fix #3400, #3401, #3402

Tests done in pyrosapp.test.py (#3406)
src/pyrosapp/admin.py
... ... @@ -69,56 +69,64 @@ class ScheduleHistoryAdmin(admin.ModelAdmin):
69 69  
70 70 class SequenceInline(admin.TabularInline):
71 71 model = Sequence
  72 + readonly_fields = ("name",)
72 73 fields = ("name",)
73 74 show_change_link = True
74 75  
75 76  
76 77 class RequestInline(admin.TabularInline):
77 78 model = Request
  79 + readonly_fields = ("name",)
78 80 fields = ("name",)
79 81 show_change_link = True
80 82  
81 83  
82 84 class AlbumInline(admin.TabularInline):
83 85 model = Album
  86 + readonly_fields = ("name",)
84 87 fields = ("name",)
85 88 show_change_link = True
86 89  
87 90  
88 91 class PlanInline(admin.TabularInline):
89 92 model = Plan
  93 + readonly_fields = ("name",)
90 94 fields = ("name",)
91 95 show_change_link = True
92 96  
93 97  
94 98 class ImageInline(admin.TabularInline):
95 99 model = Image
  100 + readonly_fields = ("name",)
96 101 fields = ("name",)
97 102 show_change_link = True
98 103  
99 104  
100 105 class DetectorInline(admin.TabularInline):
101 106 model = Detector
102   - fields = ("name",)
  107 + readonly_fields = ("device_name",)
  108 + fields = ("device_name",)
103 109 show_change_link = True
104 110  
105 111  
106 112 class PyrosUserInline(admin.TabularInline):
107 113 model = PyrosUser
108   - #fields = ("name",)
109   - fields = ("user.username",)
  114 + readonly_fields = ("user_username",)
  115 + fields = ("user_username",)
110 116 show_change_link = True
111 117  
112 118  
113 119 class FilterInline(admin.TabularInline):
114 120 model = Filter
115   - fields = ("name",)
  121 + readonly_fields = ("device_name",)
  122 + fields = ("device_name",)
116 123 show_change_link = True
117 124  
118 125  
119 126 class AlertInline(admin.TabularInline):
120 127 model = Alert
121   - fields = ("request.name",)
  128 + readonly_fields = ("request_name",)
  129 + fields = ("request_name",)
122 130 show_change_link = True
123 131  
124 132  
... ...
src/pyrosapp/models.py
... ... @@ -16,8 +16,8 @@ class Album(models.Model):
16 16 detector = models.ForeignKey('Detector', models.DO_NOTHING, related_name="albums")
17 17 name = models.CharField(max_length=45, blank=True, null=True)
18 18 desc = models.TextField(blank=True, null=True)
19   - created = models.DateTimeField(blank=True, null=True)
20   - updated = models.DateTimeField(blank=True, null=True)
  19 + created = models.DateTimeField(blank=True, null=True, auto_now_add=True)
  20 + updated = models.DateTimeField(blank=True, null=True, auto_now=True)
21 21  
22 22 class Meta:
23 23 managed = True
... ... @@ -43,7 +43,7 @@ class Alert(models.Model):
43 43 trigger_instrum = models.CharField(max_length=45, blank=True, null=True)
44 44 trigger_num = models.CharField(max_length=45, blank=True, null=True)
45 45 grb_error = models.CharField(max_length=45, blank=True, null=True)
46   - def_not_grb = models.IntegerField(blank=True, null=True)
  46 + def_not_grb = models.BooleanField()
47 47 editor = models.CharField(max_length=45, blank=True, null=True)
48 48 flag = models.CharField(max_length=45, blank=True, null=True)
49 49 idgcn_notice = models.IntegerField(blank=True, null=True)
... ... @@ -53,7 +53,11 @@ class Alert(models.Model):
53 53 db_table = 'alert'
54 54  
55 55 def __str__(self):
56   - return (self.request.name)
  56 + return str(self.request.name)
  57 +
  58 + def request_name(self):
  59 + return self.__str__()
  60 + request_name.short_description = "Name"
57 61  
58 62 class Country(models.Model):
59 63 name = models.CharField(max_length=45, blank=True, null=True)
... ... @@ -63,6 +67,7 @@ class Country(models.Model):
63 67 class Meta:
64 68 managed = True
65 69 db_table = 'country'
  70 + verbose_name_plural = "Countries"
66 71  
67 72 def __str__(self):
68 73 return (str(self.name))
... ... @@ -76,7 +81,7 @@ class Detector(models.Model):
76 81 nb_photo_y = models.IntegerField(blank=True, null=True)
77 82 photo_size_x = models.IntegerField(blank=True, null=True)
78 83 photo_size_y = models.IntegerField(blank=True, null=True)
79   - has_shutter = models.IntegerField(blank=True, null=True)
  84 + has_shutter = models.BooleanField()
80 85 equivalent_foc_len = models.CharField(max_length=45, blank=True, null=True)
81 86 acq_start = models.DateTimeField(blank=True, null=True)
82 87 acq_stop = models.DateTimeField(blank=True, null=True)
... ... @@ -91,14 +96,18 @@ class Detector(models.Model):
91 96 db_table = 'detector'
92 97  
93 98 def __str__(self):
94   - return (self.device.name)
  99 + return str(self.device.name)
  100 +
  101 + def device_name(self):
  102 + return self.__str__()
  103 + device_name.short_description = "Name"
95 104  
96 105 class Device(models.Model):
97 106 name = models.CharField(max_length=45, blank=True, null=True)
98 107 desc = models.TextField(blank=True, null=True)
99   - created = models.DateTimeField(blank=True, null=True)
100   - updated = models.DateTimeField(blank=True, null=True)
101   - is_online = models.IntegerField(blank=True, null=True)
  108 + created = models.DateTimeField(blank=True, null=True, auto_now_add=True)
  109 + updated = models.DateTimeField(blank=True, null=True, auto_now=True)
  110 + is_online = models.BooleanField()
102 111 status = models.CharField(max_length=11, blank=True, null=True)
103 112 maintenance_date = models.DateTimeField(blank=True, null=True)
104 113  
... ... @@ -120,16 +129,19 @@ class Filter(models.Model):
120 129 db_table = 'filter'
121 130  
122 131 def __str__(self):
123   - return (self.device.name)
  132 + return (str(self.device.name))
124 133  
  134 + def device_name(self):
  135 + return self.__str__()
  136 + device_name.short_description = "Name"
125 137  
126 138 class Image(models.Model):
127 139 plan = models.ForeignKey('Plan', models.CASCADE, related_name="images")
128 140 nrtanalysis = models.ForeignKey('NrtAnalysis', models.DO_NOTHING, blank=True, null=True, related_name="images")
129 141 name = models.CharField(max_length=45, blank=True, null=True)
130 142 desc = models.TextField(blank=True, null=True)
131   - created = models.DateTimeField(blank=True, null=True)
132   - updated = models.DateTimeField(blank=True, null=True)
  143 + created = models.DateTimeField(blank=True, null=True, auto_now_add=True)
  144 + updated = models.DateTimeField(blank=True, null=True, auto_now=True)
133 145 date_from_gps = models.CharField(max_length=45, blank=True, null=True)
134 146 level = models.IntegerField(blank=True, null=True)
135 147 type = models.CharField(max_length=5, blank=True, null=True)
... ... @@ -158,13 +170,14 @@ class Image(models.Model):
158 170 class NrtAnalysis(models.Model):
159 171 name = models.CharField(max_length=45, blank=True, null=True)
160 172 desc = models.TextField(blank=True, null=True)
161   - created = models.DateTimeField(blank=True, null=True)
162   - updated = models.DateTimeField(blank=True, null=True)
  173 + created = models.DateTimeField(blank=True, null=True, auto_now_add=True)
  174 + updated = models.DateTimeField(blank=True, null=True, auto_now=True)
163 175 analysis = models.TextField(blank=True, null=True)
164 176  
165 177 class Meta:
166 178 managed = True
167 179 db_table = 'nrtanalysis'
  180 + verbose_name_plural = "Nrt analyzes"
168 181  
169 182 def __str__(self):
170 183 return (str(self.name))
... ... @@ -175,13 +188,13 @@ class Plan(models.Model):
175 188 filter = models.ForeignKey(Filter, models.DO_NOTHING, related_name="plans")
176 189 name = models.CharField(max_length=45, blank=True, null=True)
177 190 desc = models.CharField(max_length=45, blank=True, null=True)
178   - created = models.DateTimeField(blank=True, null=True)
179   - updated = models.DateTimeField(blank=True, null=True)
  191 + created = models.DateTimeField(blank=True, null=True, auto_now_add=True)
  192 + updated = models.DateTimeField(blank=True, null=True, auto_now=True)
180 193 duration = models.FloatField(blank=True, null=True)
181 194 position = models.CharField(max_length=45, blank=True, null=True)
182 195 exposure_time = models.FloatField(blank=True, null=True)
183 196 nb_images = models.IntegerField(blank=True, null=True)
184   - dithering = models.IntegerField(blank=True, null=True)
  197 + dithering = models.BooleanField()
185 198  
186 199 class Meta:
187 200 managed = True
... ... @@ -191,20 +204,57 @@ class Plan(models.Model):
191 204 return (str(self.name))
192 205  
193 206  
  207 +class PyrosUser(models.Model):
  208 + user = models.OneToOneField(User, on_delete=models.CASCADE)
  209 + country = models.ForeignKey(Country, models.DO_NOTHING, related_name="pyros_users")
  210 + userlevel = models.ForeignKey('UserLevel', models.DO_NOTHING, related_name="pyros_users")
  211 + desc = models.TextField(blank=True, null=True)
  212 + desce = models.TextField(blank=True, null=True)
  213 + created = models.DateTimeField(blank=True, null=True, auto_now_add=True)
  214 + updated = models.DateTimeField(blank=True, null=True, auto_now=True)
  215 + url = models.CharField(max_length=45, blank=True, null=True)
  216 + tel1 = models.CharField(max_length=45, blank=True, null=True)
  217 + tel2 = models.CharField(max_length=45, blank=True, null=True)
  218 + address = models.CharField(max_length=45, blank=True, null=True)
  219 + last_connect = models.DateTimeField(blank=True, null=True)
  220 + cur_connect = models.DateTimeField(blank=True, null=True)
  221 + putvalid_beg = models.DateTimeField(blank=True, null=True)
  222 + putvalid_end = models.DateTimeField(blank=True, null=True)
  223 + acqvalid_beg = models.CharField(max_length=45, blank=True, null=True)
  224 + acqvalid_end = models.CharField(max_length=45, blank=True, null=True)
  225 + quota = models.FloatField(blank=True, null=True)
  226 + quota_rea = models.FloatField(blank=True, null=True)
  227 + u_priority = models.IntegerField(blank=True, null=True)
  228 + p_priority = models.IntegerField(blank=True, null=True)
  229 + dir_level = models.IntegerField(blank=True, null=True)
  230 + can_del_void_req = models.BooleanField()
  231 +
  232 + class Meta:
  233 + managed = True
  234 + db_table = 'pyros_user'
  235 +
  236 + def __str__(self):
  237 + return (str(self.user.get_username()))
  238 +
  239 + def user_username(self):
  240 + return self.__str__()
  241 + user_username.short_description = "Username"
  242 +
  243 +
194 244 class Request(models.Model):
195 245 pyros_user = models.ForeignKey('PyrosUser', models.DO_NOTHING, related_name="requests")
196 246 scientificprogram = models.ForeignKey('ScientificProgram', models.DO_NOTHING, related_name="requests")
197 247 name = models.CharField(max_length=45, blank=True, null=True)
198 248 desc = models.TextField(blank=True, null=True)
199   - created = models.DateTimeField(blank=True, null=True)
200   - updated = models.DateTimeField(blank=True, null=True)
  249 + created = models.DateTimeField(blank=True, null=True, auto_now_add=True)
  250 + updated = models.DateTimeField(blank=True, null=True, auto_now=True)
201 251 #is_alert = models.IntegerField(blank=True, null=True)
202   - is_alert = models.BooleanField()
  252 + is_alert = models.BooleanField(default=False)
203 253 type = models.CharField(max_length=8, blank=True, null=True)
204 254 status = models.CharField(max_length=10, blank=True, null=True)
205 255 target_or_theme = models.CharField(max_length=45, blank=True, null=True)
206 256 priority = models.IntegerField(blank=True, null=True)
207   - autodeposit = models.IntegerField(blank=True, null=True)
  257 + autodeposit = models.BooleanField(default=False)
208 258 checkpoint = models.CharField(max_length=45, blank=True, null=True)
209 259 flag = models.CharField(max_length=45, blank=True, null=True)
210 260  
... ... @@ -217,7 +267,7 @@ class Request(models.Model):
217 267  
218 268  
219 269 class Schedule(models.Model):
220   - created = models.DateTimeField(blank=True, null=True)
  270 + created = models.DateTimeField(blank=True, null=True, auto_now_add=True)
221 271 day_start = models.DateTimeField(blank=True, null=True)
222 272 day_stop = models.DateTimeField(blank=True, null=True)
223 273 flag = models.CharField(max_length=45, blank=True, null=True)
... ... @@ -232,7 +282,7 @@ class Schedule(models.Model):
232 282  
233 283 class ScheduleHistory(models.Model):
234 284 sequences = models.ManyToManyField('Sequence', related_name='schedulehistories')
235   - created = models.DateTimeField(blank=True, null=True)
  285 + created = models.DateTimeField(blank=True, null=True, auto_now_add=True)
236 286 day_start = models.DateTimeField(blank=True, null=True)
237 287 day_stop = models.DateTimeField(blank=True, null=True)
238 288 flag = models.CharField(max_length=45, blank=True, null=True)
... ... @@ -240,6 +290,7 @@ class ScheduleHistory(models.Model):
240 290 class Meta:
241 291 managed = True
242 292 db_table = 'schedulehistory'
  293 + verbose_name_plural = "Schedule histories"
243 294  
244 295 def __str__(self):
245 296 return (str(self.created))
... ... @@ -265,13 +316,13 @@ class Sequence(models.Model):
265 316 schedule = models.ForeignKey(Schedule, models.DO_NOTHING, related_name="sequences")
266 317 name = models.CharField(max_length=45, blank=True, null=True)
267 318 desc = models.TextField(blank=True, null=True)
268   - created = models.DateTimeField(blank=True, null=True)
269   - updated = models.DateTimeField(blank=True, null=True)
270   - is_alert = models.IntegerField(blank=True, null=True)
  319 + created = models.DateTimeField(blank=True, null=True, auto_now_add=True)
  320 + updated = models.DateTimeField(blank=True, null=True, auto_now=True)
  321 + is_alert = models.BooleanField()
271 322 status = models.CharField(max_length=11, blank=True, null=True)
272 323 duration = models.FloatField(blank=True, null=True)
273 324 pointing = models.CharField(max_length=45, blank=True, null=True)
274   - with_drift = models.IntegerField(blank=True, null=True)
  325 + with_drift = models.BooleanField()
275 326 priority = models.IntegerField(blank=True, null=True)
276 327 analysis_method = models.CharField(max_length=45, blank=True, null=True)
277 328 exec_start = models.DateTimeField()
... ... @@ -281,9 +332,9 @@ class Sequence(models.Model):
281 332 type = models.CharField(max_length=6, blank=True, null=True)
282 333 img_current = models.CharField(max_length=45, blank=True, null=True)
283 334 img_total = models.CharField(max_length=45, blank=True, null=True)
284   - not_obs = models.IntegerField(blank=True, null=True)
285   - obsolete = models.IntegerField(blank=True, null=True)
286   - processing = models.IntegerField(blank=True, null=True)
  335 + not_obs = models.BooleanField()
  336 + obsolete = models.BooleanField(default=False)
  337 + processing = models.BooleanField(default=False)
287 338 flag = models.CharField(max_length=45, blank=True, null=True)
288 339  
289 340 class Meta:
... ... @@ -308,7 +359,7 @@ class SequenceType(models.Model):
308 359  
309 360  
310 361 class SiteWatch(models.Model):
311   - updated = models.DateTimeField(blank=True, null=True)
  362 + updated = models.DateTimeField(blank=True, null=True, auto_now=True)
312 363 lights = models.CharField(max_length=45, blank=True, null=True)
313 364 dome = models.CharField(max_length=45, blank=True, null=True)
314 365 doors = models.CharField(max_length=45, blank=True, null=True)
... ... @@ -317,6 +368,7 @@ class SiteWatch(models.Model):
317 368 class Meta:
318 369 managed = True
319 370 db_table = 'sitewatch'
  371 + verbose_name_plural = "Site watches"
320 372  
321 373 def __str__(self):
322 374 return (str(self.updated))
... ... @@ -328,6 +380,7 @@ class SiteWatchHistory(models.Model):
328 380 class Meta:
329 381 managed = True
330 382 db_table = 'sitewatchhistory'
  383 + verbose_name_plural = "Site watch histories"
331 384  
332 385  
333 386 class StrategyObs(models.Model):
... ... @@ -338,6 +391,7 @@ class StrategyObs(models.Model):
338 391 class Meta:
339 392 managed = True
340 393 db_table = 'strategyobs'
  394 + verbose_name_plural = "Strategy obs"
341 395  
342 396 def __str__(self):
343 397 return (str(self.name))
... ... @@ -374,40 +428,6 @@ class Telescope(models.Model):
374 428 return (self.device.name)
375 429  
376 430  
377   -class PyrosUser(models.Model):
378   - user = models.OneToOneField(User, on_delete=models.CASCADE)
379   - country = models.ForeignKey(Country, models.DO_NOTHING, related_name="pyros_users")
380   - userlevel = models.ForeignKey('UserLevel', models.DO_NOTHING, related_name="pyros_users")
381   - desc = models.TextField(blank=True, null=True)
382   - desce = models.TextField(blank=True, null=True)
383   - created = models.DateTimeField(blank=True, null=True)
384   - updated = models.DateTimeField(blank=True, null=True)
385   - url = models.CharField(max_length=45, blank=True, null=True)
386   - tel1 = models.CharField(max_length=45, blank=True, null=True)
387   - tel2 = models.CharField(max_length=45, blank=True, null=True)
388   - address = models.CharField(max_length=45, blank=True, null=True)
389   - last_connect = models.DateTimeField(blank=True, null=True)
390   - cur_connect = models.DateTimeField(blank=True, null=True)
391   - putvalid_beg = models.DateTimeField(blank=True, null=True)
392   - putvalid_end = models.DateTimeField(blank=True, null=True)
393   - acqvalid_beg = models.CharField(max_length=45, blank=True, null=True)
394   - acqvalid_end = models.CharField(max_length=45, blank=True, null=True)
395   - quota = models.FloatField(blank=True, null=True)
396   - quota_rea = models.FloatField(blank=True, null=True)
397   - u_priority = models.IntegerField(blank=True, null=True)
398   - p_priority = models.IntegerField(blank=True, null=True)
399   - dir_level = models.IntegerField(blank=True, null=True)
400   - can_del_void_req = models.IntegerField(blank=True, null=True)
401   -
402   - class Meta:
403   - managed = True
404   - db_table = 'pyros_user'
405   -
406   - def __str__(self):
407   - #return (str(self.name))
408   - return (str(self.user.username))
409   -
410   -
411 431 class UserLevel(models.Model):
412 432 name = models.CharField(max_length=45, blank=True, null=True)
413 433 desc = models.TextField(blank=True, null=True)
... ... @@ -437,13 +457,14 @@ class WeatherWatch(models.Model):
437 457 class Meta:
438 458 managed = True
439 459 db_table = 'weatherwatch'
  460 + verbose_name_plural = "Weather watches"
440 461  
441 462 def __str__(self):
442 463 return (str(self.updated))
443 464  
444 465  
445 466 class WeatherWatchHistory(models.Model):
446   - datetime = models.DateTimeField(blank=True, null=True)
  467 + datetime = models.DateTimeField(blank=True, null=True, auto_now_add=True)
447 468 humid_int = models.CharField(max_length=45, blank=True, null=True)
448 469 humid_ext = models.CharField(max_length=45, blank=True, null=True)
449 470 wind = models.CharField(max_length=45, blank=True, null=True)
... ... @@ -457,6 +478,7 @@ class WeatherWatchHistory(models.Model):
457 478 class Meta:
458 479 managed = True
459 480 db_table = 'weatherwatchhistory'
  481 + verbose_name_plural = "Weather watch histories"
460 482  
461 483 def __str__(self):
462 484 return (str(self.datetime))
... ...
src/pyrosapp/tests.py
1 1 from django.test import TestCase
  2 +from pyrosapp.models import *
  3 +from django.contrib.auth.models import User
  4 +from django.utils import timezone
2 5  
3   -# Create your tests here.
  6 +class CountryTests(TestCase):
  7 + def test_creation(self):
  8 + Country.objects.create(name="France", desc="Test", quota=1)
  9 + france = Country.objects.get(name="France")
  10 + self.assertEqual(france.name, "France")
  11 + self.assertEqual(france.desc, "Test")
  12 + self.assertEqual(france.quota, 1)
  13 + france.quota = -1
  14 + france.delete()
  15 + france.save()
  16 + Country.objects.create(name="Mexique")
  17 + countries = Country.objects.all()
  18 + self.assertEqual(countries.count(), 2)
  19 + countries[0].name = "Toto"
  20 + countries[0].save()
  21 +
  22 +class DeviceTests(TestCase):
  23 + def test_creation(self):
  24 + device = Device.objects.create()
  25 + countries = Country.objects.all()
  26 + self.assertEqual(countries.count(), 0, "perdu !")
  27 +
  28 +class RequestTests(TestCase):
  29 + def setUp(self):
  30 + strat1 = StrategyObs.objects.create(name="strat1")
  31 + france = Country.objects.create(name="France")
  32 + admin = UserLevel.objects.create(name="Admin")
  33 + usr1 = User.objects.create(username="Haribo")
  34 + haribo = PyrosUser.objects.create(user=usr1, country=france, userlevel=admin)
  35 + sp1 = ScientificProgram.objects.create(name="sp1")
  36 + req1 = Request.objects.create(name="req1", pyros_user=haribo, scientificprogram=sp1)
  37 + Alert.objects.create(strategyobs=strat1, request=req1)
  38 +
  39 + sched = Schedule.objects.create()
  40 + sqt = SequenceType.objects.create()
  41 + seq1 = Sequence.objects.create(name="seq1", request=req1, sequencetype=sqt, schedule=sched, exec_start=timezone.now())
  42 +
  43 + dev_tel = Device.objects.create(name="telescope")
  44 + dev_det = Device.objects.create(name="detector")
  45 + tel = Telescope.objects.create(device=dev_tel)
  46 + det = Detector.objects.create(device=dev_det, telescope=tel)
  47 + alb1 = Album.objects.create(name="alb1", sequence=seq1, detector=det)
  48 +
  49 + dev_fil = Device.objects.create(name="filter")
  50 + fil = Filter.objects.create(device=dev_fil, detector=det)
  51 + plan1 = Plan.objects.create(name="plan1", album=alb1, filter=fil)
  52 + img1 = Image.objects.create(name="img1", plan=plan1)
  53 + img2 = Image.objects.create(name="img2", plan=plan1)
  54 +
  55 + def test_request_access(self):
  56 + alert = Alert.objects.get()
  57 + self.assertEqual(alert.request.name, "req1")
  58 +
  59 + req1 = Request.objects.get(name="req1")
  60 + req1.name = "reqtiti"
  61 + req1.save()
  62 + self.assertEqual(alert.request.name, "req1") # j'ai saved req1, pourtant alert1.request.name est toujours le même
  63 +
  64 + alert = Alert.objects.get()
  65 + self.assertEqual(alert.request.name, "reqtiti") # j'ai refait un get de mon alert, donc c'est mis à jour
  66 +
  67 + alert.request.name = "reqtoto"
  68 + alert.save()
  69 + self.assertEqual(req1.name, "reqtiti")
  70 + self.assertEqual(alert.request.name, "reqtoto")
  71 +
  72 + req1 = Request.objects.get()
  73 + self.assertEqual(req1.name, "reqtiti")
  74 +
  75 + alert.request.save()
  76 + req1 = Request.objects.get()
  77 + self.assertEqual(req1.name, "reqtoto")
  78 +
  79 + def test_reinit_base(self):
  80 + req1 = Request.objects.get()
  81 + self.assertEqual(req1.name, "req1")
  82 +
  83 + def test_full_request(self):
  84 + req1 = Request.objects.get()
  85 + self.assertEqual(req1.sequences.count(), 1)
  86 + albums = req1.sequences.all()[0].albums
  87 + self.assertEqual(albums.count(), 1)
  88 + images = albums.all()[0].plans.all()[0].images
  89 + self.assertEqual(images.count(), 2)
  90 + img1 = images.get(name="img1")
  91 + img1.name = "img1.1"
  92 + img11 = req1.sequences.get().albums.get().plans.get().images.get(name="img1") # j'ai toujours pas sauvegardé mon image
  93 + img1.save()
  94 + img11 = req1.sequences.get().albums.get().plans.get().images.get(name="img1.1") # j'ai sauvegardé mon image
  95 +
  96 + req1 = Request.objects.get()
  97 + img1 = req1.sequences.get().albums.get().plans.get().images.get(name="img1.1")
  98 +
  99 + img11 = Image.objects.get(name="img1.1")
  100 + img11.name = "img1.2"
  101 + img11.save()
  102 +
  103 + self.assertEqual(img1.name, "img1.1") # img1 et img11 sont différents
  104 + img1 = req1.sequences.get().albums.get().plans.get().images.get(name="img1.2")
... ...