version.py 3.31 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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


class VersionSerializer(BaseModelSerializer):
    """
    Custom serializer for the (reversion) version model
    """

    data = serializers.SerializerMethodField()

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
    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.config.viewsets import get_viewsets_info

            # A little bit of optimization to easily find the serializer class associated with a model
            cls.serializers_mapping = dict()
            viewsets = map(
                lambda v: v.Viewset,
                get_viewsets_info(requires_testing="smart", is_api_view=False),
            )

            for viewset in 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 viewsets:
                model = viewset().get_serializer_class().Meta.model
                try:
                    cls.serializers_mapping[model.__name__] = model.get_serializer()
                except AttributeError:
                    pass
        return cls.serializers_mapping

50
51
52
53
54
55
56
57
58
59
60
61
    def get_data(self, obj):
        """
        Serilizer 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,
62
63
            print(self.get_serializers_mapping())
            obj_serializer = self.get_serializers_mapping()[type(tmp.object).__name__]
64
65
66
67
68
            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 !
Florent Chehab's avatar
Florent Chehab committed
69
            # This might be due to an updated model structure at some point.
70
            obj.delete()
Florent Chehab's avatar
Florent Chehab committed
71
72
            # We take care of the nb_versions field update with signals.
            # So it will remain coherent.
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
            return None

    class Meta:
        model = Version
        fields = ("data", "id")


class VersionViewSet(BaseModelViewSet):
    """
    Viewset for the versions
    """

    serializer_class = VersionSerializer

    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)