def delete(self, *args, **kwargs): """ Custom delete for Entry. Sets date_deleted and deleted_by instead of a hard delete. Extracts user for deleted_by from request, unless given an argument. """ self.date_deleted = datetime.datetime.now() if not self.deleted_by: request = find_request() if request and request.user.is_authenticated(): self.deleted_by = request.user # Call the real save() method, NOT the delete() super(Entry, self).save(*args, **kwargs)
def save(self, *args, **kwargs): """ Custom save for Entry. Sets created_by or last_changed_by depending on if the object is being created or modified. If the field in question has not been specified in the method call the user will be extracted from the request. When modifying rather than creating, checks if there is a corresponding History model and saves the old version of the object there. History will not be saved if: There is no History model. None of the fields that the History model tracks has been changed. The change was made by the same user as the last change, and within 5 min of the last change. """ if not self.id: # This is a new item, set created_by if not self.created_by: # created_by not in args, find the request to get the user request = find_request() if request and request.user.is_authenticated(): self.created_by = request.user else: # Modyfing object, set last_changed_by if not self.last_changed_by: # last_changed_by not in args, find the request to get the user request = find_request() if request and request.user.is_authenticated(): self.last_changed_by = request.user # Check if there is a history model, and if so handle history history_name = self.__class__.__name__ + "History" history_model = get_model(self._meta.app_label, history_name) if history_model: # Validate that the origin field exists if "origin" not in history_model._meta.get_all_field_names(): error = """ All History models must contain a ForeignKey named "origin", pointing to the model that it tracks history for." """ raise ImproperlyConfigured(error) # We have a history model, check time and user needs_history = False current_object = self.__class__.objects.get(pk=self.pk) last_changer = current_object.last_changed_by if not last_changer: # Not changed, or changed by anonymous. Use created_by last_changer = current_object.created_by if not last_changer or last_changer != self.last_changed_by: # Not edited by the same user as before, save history needs_history = True else: # Changed by the same user, check timestamps last_changed = current_object.date_last_changed if not last_changed: # Has not been changed before, use date_created instead last_changed = current_object.date_created time_d = datetime.timedelta(minutes=5) if last_changed < datetime.datetime.now() - time_d: needs_history = True # Check if fields have changed if needs_history: changed = False history_fields = {} for field_n in history_model._meta.get_all_field_names(): # Skip id, created_by, date_created, origin s_f = ["id", "created_by", "date_created", "origin"] if field_n in s_f: continue # Check all other fields field = getattr(current_object, field_n) if field != getattr(self, field_n): changed = True history_fields[field_n] = getattr(self, field_n) if changed: # All requirements for history has been checked, # save the a history item history_fields['created_by'] = self.last_changed_by history_fields['origin'] = self try: history_model.objects.create(**history_fields) except TypeError: error = """ TypeError encountered on field when creating history. History can only be used on "simple" fields, advanced fields like ManyToManyField cannot be tracked. """ raise ImproperlyConfigured(error) # Call the real save() method. # Setting hierarchy calls save twice as it needs the pk to set the # hierarchy. If the save originated from a objects.create force_insert # will be one. If we see this, foce_update instead if self.pk: kwargs['force_insert'] = False kwargs['force_update'] = True super(Entry, self).save(*args, **kwargs) else: super(Entry, self).save(*args, **kwargs)