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

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

from django.contrib.contenttypes.models import ContentType 

from django.core import serializers as djangoSerializers 

from django.core.serializers.base import DeserializationError 

from rest_framework import serializers 

from reversion.models import Version 

 

from backend_app.models.abstract.base import BaseModelSerializer, BaseModelViewSet 

from backend_app.permissions.app_permissions import ReadOnly 

 

 

class VersionSerializer(BaseModelSerializer): 

""" 

Custom serializer for the (reversion) version model 

""" 

 

data = serializers.SerializerMethodField() 

 

serializers_mapping = None 

 

@classmethod 

def get_serializers_mapping(cls) -> dict: 

""" 

Function that returns a mapping from model name to the serializer 

class that should be used to return the versioned data. 

""" 

if cls.serializers_mapping is None: 

# Prevent cyclic imports 

from backend_app.viewsets import ALL_API_VIEWSETS 

 

# A little bit of optimization to easily find the serializer class associated with a model 

cls.serializers_mapping = dict() 

 

for viewset in ALL_API_VIEWSETS: 

serializer = viewset().get_serializer_class() 

model = serializer.Meta.model 

cls.serializers_mapping[model.__name__] = serializer 

 

# Override if models has a get_serializer method 

for viewset in ALL_API_VIEWSETS: 

model = viewset().get_serializer_class().Meta.model 

try: 

cls.serializers_mapping[model.__name__] = model.get_serializer() 

except AttributeError: 

pass 

return cls.serializers_mapping 

 

def get_data(self, obj): 

""" 

Serializer for the data field 

""" 

data = obj.serialized_data 

 

try: 

# We try to deserialize the version 

tmp = list( 

djangoSerializers.deserialize(obj.format, data, ignorenonexistent=True) 

)[0] 

# Version is valid, 

obj_serializer = self.get_serializers_mapping()[type(tmp.object).__name__] 

new_context = dict(self.context) 

new_context["view"].action = "list" 

return obj_serializer(tmp.object, context=new_context).data 

except (DeserializationError, djangoSerializers.SerializerDoesNotExist): 

# The version is not valid regarding the model, we should delete it ! 

# This might be due to an updated model structure at some point. 

obj.delete() 

# We take care of the nb_versions field update with signals. 

# So it will remain coherent. 

return None 

 

class Meta: 

model = Version 

fields = ("data", "id") 

 

 

class VersionViewSet(BaseModelViewSet): 

""" 

Viewset for the versions 

""" 

 

serializer_class = VersionSerializer 

permission_classes = (ReadOnly,) 

end_point_route = ( 

r"versions/(?P<content_type_id>[0-9]+)/(?P<object_pk>[0-9A-Za-z]+)" 

) 

 

def get_queryset(self): 

content_type_id = self.kwargs["content_type_id"] 

object_pk = self.kwargs["object_pk"] 

ct = ContentType.objects.get_for_id(content_type_id) 

model = ct.model_class() 

obj = model.objects.get(pk=object_pk) 

return Version.objects.get_for_object(obj).order_by("revision_id")