Guest User

Untitled

a guest
Dec 13th, 2018
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.39 KB | None | 0 0
  1. from django.core.exceptions import FieldDoesNotExist
  2. from django_extensions.db.fields import json
  3. from rest_framework.decorators import list_route, detail_route
  4. from reversion.models import Version
  5.  
  6. from common.pagination import SmallPagination, HistoryDiffPagination
  7. from history.serializers import HistoryUserSerializer
  8. from history.views import get_serialized_history
  9.  
  10.  
  11. class HistoryDiffPaginator(Paginator):
  12.  
  13. @cached_property
  14. def count(self):
  15. versions_count = super().count
  16. if not versions_count:
  17. return 0
  18. return versions_count - 1
  19.  
  20. def page(self, number):
  21. """
  22. The same as Paginator but does top + 1 to get paginated diff list.
  23. To build one object in diff list we need 2 Versions.
  24. So for example to get 10 items per page we need operate with 11 Versions.
  25. """
  26. number = self.validate_number(number)
  27. bottom = (number - 1) * self.per_page
  28. top = bottom + self.per_page
  29. if top + self.orphans >= self.count:
  30. top = self.count
  31. return self._get_page(self.object_list[bottom:top+1], number, self)
  32.  
  33.  
  34. def pk_to_str(model, pk):
  35. instance = model.objects.filter(pk=pk).first()
  36. if not instance:
  37. return pk
  38.  
  39. if hasattr(instance, 'name'):
  40. return instance.name
  41. return str(instance)
  42.  
  43.  
  44. def get_diff_list(versions_list, instance) -> list:
  45. """
  46. Versions MUST be ordered: order_by('revision__date_created')!
  47. """
  48.  
  49. model = instance._meta.model
  50.  
  51. diff_list = []
  52. for h in range(len(versions_list) - 1):
  53. prev_version = versions_list[h]
  54. prev_version_data = json.loads(prev_version.serialized_data)[0]['fields']
  55.  
  56. new_version = versions_list[h + 1]
  57. new_version_data = json.loads(new_version.serialized_data)[0]['fields']
  58.  
  59. diff_data = []
  60. for field_name in new_version_data.keys():
  61. if field_name in ('updated_at', 'updated_by'):
  62. continue
  63. new_value = new_version_data.get(field_name)
  64. prev_value = prev_version_data.get(field_name)
  65.  
  66. if new_value != prev_value:
  67.  
  68. try:
  69. model_field = model._meta.get_field(field_name)
  70. except FieldDoesNotExist: # related DB column was removed
  71. diff_data.append({
  72. 'field': field_name,
  73. 'field_verbose_name': field_name,
  74. 'previous': prev_value,
  75. 'new': new_value
  76. })
  77. else:
  78. related_field_type = model_field.get_internal_type()
  79. if related_field_type == 'ForeignKey':
  80. related_model = model_field.rel.to
  81. if new_value:
  82. new_value = pk_to_str(related_model, new_value)
  83. if prev_value:
  84. prev_value = pk_to_str(related_model, prev_value)
  85. elif related_field_type == 'ManyToManyField':
  86. related_model = model_field.rel.to
  87. new_value = ', '.join(
  88. [pk_to_str(related_model, new_id) for new_id in new_value])
  89. prev_value = ', '.join(
  90. [pk_to_str(related_model, prev_id) for prev_id in prev_value])
  91.  
  92. diff_data.append({
  93. 'field': field_name,
  94. 'field_verbose_name': model_field.verbose_name,
  95. 'previous': prev_value,
  96. 'new': new_value
  97. })
  98.  
  99. diff_list.append({
  100. 'revision_user': HistoryUserSerializer(new_version.revision.user).data,
  101. 'previous_version': prev_version.pk,
  102. 'new_version': new_version.pk,
  103. 'date_created': new_version.revision.date_created,
  104. 'diff_data': diff_data,
  105. })
  106. return diff_list
  107.  
  108.  
  109. class HistoryMixin:
  110. @detail_route(methods=['get'])
  111. def object_history(self, request, pk=None, **kwargs):
  112. instance = self.get_object()
  113.  
  114. history = Version.objects.get_for_object(instance).prefetch_related(
  115. 'object').select_related().select_related('revision__user')
  116.  
  117. paginator = SmallPagination()
  118. result_page = paginator.paginate_queryset(get_serialized_history(history), request)
  119. return paginator.get_paginated_response(result_page)
  120.  
  121. @list_route(methods=['get'])
  122. def history(self, request, **kwargs):
  123. model = self.queryset.model
  124. history = Version.objects.get_for_model(model)
  125. serialized_history = get_serialized_history(history)
  126. delete_history = Version.objects.get_deleted(model)
  127. serialized_history.extend(get_serialized_history(delete_history))
  128.  
  129. paginator = SmallPagination()
  130. result_page = paginator.paginate_queryset(serialized_history, request)
  131. return paginator.get_paginated_response(result_page)
  132.  
  133. @detail_route(methods=['get'])
  134. def diff_list(self, request, pk=None):
  135. instance = self.get_object()
  136.  
  137. history = Version.objects.get_for_object(instance).prefetch_related(
  138. 'object').select_related('revision__user').order_by('revision__date_created')
  139.  
  140. paginator = HistoryDiffPagination()
  141. page = paginator.paginate_queryset(history, request)
  142.  
  143. return paginator.get_paginated_response(get_diff_list(page, instance=instance))
Add Comment
Please, Sign In to add comment