Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

2 

3Abstract 

4-------- 

5 

6The history package provides an abstract model for implementing a log of historical activity on other models. For a 

7practical implementation, see ``superdjango.contrib.history``. 

8 

9Usage 

10----- 

11 

12Implementing Audit History 

13.......................... 

14 

15You may create your own history by extending :py:class:`superdjango.db.history.models.HistoryModel`. 

16 

17.. code-block:: python 

18 

19 # myapp/models.py 

20 from superdjango.db.history.models import HistoryModel 

21 

22 class History(HistoryModel): 

23 

24 class Meta: 

25 get_latest_by = "added_dt" 

26 ordering = ["-added_dt"] 

27 verbose_name = _("Log Entry") 

28 verbose_name_plural = _("Log Entries") 

29 

30See the ``admin`` and ``ui`` modules of this package for implementing Django Admin and SuperDjango UI user interfaces. 

31 

32Creating an Audit Trail 

33....................... 

34 

35Your view must call the ``log`` method: 

36 

37.. code-block:: python 

38 

39 # myapp/views.py 

40 from .models import History 

41 

42 class CreateTodo(CreateView): 

43 ... 

44 

45 def form_valid(self, form): 

46 self.object = form.save() 

47 

48 History.log(self.object, self.request.user, History.CREATE) 

49 

50 ... 

51 

52Tracking Changes to Fields 

53.......................... 

54 

55The :py:class:`superdjango.db.history.utils.FieldChange` may be used to assist with tracking changes to fields. The 

56:py:func:`superdjango.db.history.utils.get_field_changes` is also provided as a shortcut for creating ``FieldChange`` 

57instances. 

58 

59.. code-block:: python 

60 

61 # myapp/models.py 

62 from superdjango.db.history.models import HistoryModel 

63 

64 class History(HistoryModel): 

65 

66 field_changes = models.TextField( 

67 blank=True, 

68 null=True 

69 ) 

70 

71 class Meta: 

72 get_latest_by = "added_dt" 

73 ordering = ["-added_dt"] 

74 verbose_name = _("Log Entry") 

75 verbose_name_plural = _("Log Entries") 

76 

77 @classmethod 

78 def log_field_changes(cls, instance, verb, fields=None): 

79 if fields is None: 

80 return 

81 

82 a = list() 

83 for change in fields: 

84 a.append(str(change)) 

85 

86 instance.field_changes = "\\n".join(a) 

87 

88 # myapp/views.py 

89 from superdjango.db.history.utils import get_field_changes 

90 from .models import History 

91 

92 class UpdateTodo(UpdateView): 

93 ... 

94 

95 def form_valid(self, form): 

96 self.object = form.save() 

97 

98 field_changes = get_field_changes(form, self.model, record=self.object) 

99 

100 History.log(self.object, self.request.user, History.UPDATE, fields=field_changes) 

101 

102 ... 

103 

104You could also implement a separate model to record each field change and connect it to the history record. 

105 

106.. code-block:: python 

107 

108 # myapp/models.py 

109 from superdjango.db.history.models import HistoryModel 

110 

111 class History(HistoryModel): 

112 ... 

113 

114 @classmethod 

115 def log_field_changes(cls, instance, verb, fields=None): 

116 if fields is None: 

117 return 

118 

119 a = list() 

120 for change in fields: 

121 field_history = FieldHistory( 

122 field_label=change.field_label, 

123 field_name=change.field_name 

124 history=instance, 

125 new_value=change.new_value, 

126 old_value=change.old_value, 

127 ) 

128 field_history.save() 

129 

130 class FieldHistory(models.Model): 

131 

132 field_label = models.CharField( 

133 max_length=256 

134 ) 

135 

136 field_name = models.CharField( 

137 max_length=256 

138 ) 

139 

140 history = models.ForeignKey( 

141 History, 

142 on_delete=models.CASCADE, 

143 related_name="field_changes", 

144 verbose_name=_("History") 

145 ) 

146 

147 new_value = models.TextField( 

148 blank=True, 

149 null=True 

150 ) 

151 

152 old_value = models.TextField( 

153 blank=True, 

154 null=True 

155 ) 

156 

157 class Meta: 

158 ordering = ["field_label"] 

159 verbose_name = _("Field History") 

160 verbose_name_plural = _("Field Histories") 

161 

162 def __str__(self): 

163 return "%s: %s -> %s" % (self.field_label, self.old_value, self.new_value) 

164 

165 

166Note that custom views or UI would be required to display the field history records. 

167 

168""" 

169__author__ = "Shawn Davis <shawn@superdjango.com>" 

170__maintainer__ = "Shawn Davis <shawn@superdjango.com>" 

171__version__ = "0.7.0-p"