Coverage for src / mesh / models / orm / base_models.py: 98%

46 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-05-04 12:41 +0000

1from __future__ import annotations 

2 

3from typing import TYPE_CHECKING 

4 

5from django.conf import settings 

6from django.contrib.auth import get_user_model 

7from django.db import models 

8from django.utils import timezone 

9from django.utils.translation import gettext_lazy as _ 

10 

11if TYPE_CHECKING: 

12 from .user_models import User 

13 

14 

15class BaseChangeTrackingModel(models.Model): 

16 """ 

17 Base model used to perform simple "change tracking" on models. 

18 It adds 4 fields to the model: 

19 - `date_created` The creation date of the object. 

20 - `created_by` The user creating the object. 

21 - `date_last_modified` The date of the last modification performed. 

22 - `last_modified_by` The user who performed the last modification. 

23 

24 The data is automatically updated when calling the model `save()` method. 

25 The code looks in the `_user` attribute to update the tracking fields. The views 

26 must inject it in the instance before saving it. 

27 """ 

28 

29 # Instance of the user creating / modifying the model used to automatically fill 

30 # the `created_by` and `last_modified_by` fields. 

31 _user: User | None = None 

32 # Whether to prevent the update of the last modification fields. 

33 do_not_update = False 

34 date_created = models.DateTimeField( 

35 verbose_name=_("Creation date"), 

36 default=timezone.now, 

37 null=True, 

38 editable=False, 

39 ) 

40 created_by = models.ForeignKey["User"]( 

41 settings.AUTH_USER_MODEL, 

42 verbose_name=_("Created by"), 

43 on_delete=models.SET_NULL, 

44 null=True, 

45 help_text=_("Automatically filled on save."), 

46 editable=False, 

47 related_name="+", 

48 ) 

49 date_last_modified = models.DateTimeField( 

50 verbose_name=_("Last modification date"), 

51 default=timezone.now, 

52 null=True, 

53 editable=False, 

54 ) 

55 last_modified_by = models.ForeignKey["User"]( 

56 settings.AUTH_USER_MODEL, 

57 verbose_name=_("Last modified by"), 

58 on_delete=models.SET_NULL, 

59 null=True, 

60 help_text=_("Automatically filled on save."), 

61 editable=False, 

62 related_name="+", 

63 ) 

64 

65 class Meta: 

66 abstract = True 

67 

68 def override_saved_date( 

69 self, 

70 *args, 

71 date_created: timezone.datetime | None = None, 

72 date_last_modified: timezone.datetime | None = None, 

73 created_by_user: User | None = None, 

74 last_modified_by_user: User | None = None, 

75 ): 

76 self.do_not_update = True 

77 if date_created: 

78 self.date_created = date_created 

79 if date_last_modified: 

80 self.date_last_modified = date_last_modified 

81 if created_by_user: 

82 self.created_by_id = created_by_user.pk 

83 if last_modified_by_user: 

84 self.last_modified_by_id = last_modified_by_user.pk 

85 

86 def save(self, *args, **kwargs) -> None: 

87 """ 

88 Update the tracking data before save: 

89 - Update the creation data if the object is new 

90 - Update the last modification data if the `_request` attribute is set 

91 """ 

92 UserModel = get_user_model() 

93 if self.do_not_update: 

94 return super().save(*args, **kwargs) 

95 

96 if self._state.adding: 

97 self.date_created = timezone.now() 

98 if self._user and isinstance(self._user, UserModel): 

99 self.created_by_id = self._user.pk 

100 

101 if not self.do_not_update: 

102 self.date_last_modified = timezone.now() 

103 if self._user and isinstance(self._user, UserModel): 

104 self.last_modified_by_id = self._user.pk 

105 # self.date_last_modified = timezone.now() 

106 # if self._user and isinstance(self._user, UserModel): 

107 # self.last_modified_by_id = self._user.pk 

108 

109 super().save(*args, **kwargs) 

110 

111 

112class BaseSubmittableModel(models.Model): 

113 """ 

114 Base model "mixin" for model to be effectively submitted 

115 (different action from just saving the model). 

116 """ 

117 

118 submitted = models.BooleanField(verbose_name=_("Submitted"), default=False, editable=False) 

119 date_submitted = models.DateTimeField( 

120 verbose_name=_("Submitted on"), editable=False, null=True 

121 ) 

122 

123 class Meta: 

124 abstract = True 

125 

126 def is_submittable(self) -> bool: 

127 return True