myModelVersionned.py 3.21 KB
Newer Older
Florent Chehab's avatar
Florent Chehab committed
1
2
from backend_app.models.abstract.my_model import MyModel, MyModelSerializer, MyModelViewSet
from backend_app.signals.__squash_revision_by_user import new_revision_saved
3
from rest_framework import serializers, mixins, viewsets
Florent Chehab's avatar
Florent Chehab committed
4
import reversion
5
6
7
8
from reversion.models import Version
from django.contrib.contenttypes.models import ContentType
from django.core.serializers.base import DeserializationError
from django.core import serializers as djangoSerializers
Florent Chehab's avatar
Florent Chehab committed
9
10
from backend_app.utils import get_viewset_permissions
from backend_app.custom import MySerializerWithJSON
Florent Chehab's avatar
Florent Chehab committed
11
12
13
14


class MyModelVersionned(MyModel):

15
16
    @classmethod
    def get_serializer(cls):
17
18
        """
            This function is required for handling
19
            versioning easily.
20
21
            You have to put the correct value in each subclass
        """
22
        raise Exception("Get_serializer must be redifined in subclass")
23

Florent Chehab's avatar
Florent Chehab committed
24
25
26
27
28
    class Meta:
        abstract = True


class MyModelVersionnedSerializer(MyModelSerializer):
29
30
31
32
    nb_versions = serializers.SerializerMethodField()
    content_type_id = serializers.SerializerMethodField()

    def get_nb_versions(self, obj):
Florent Chehab's avatar
Florent Chehab committed
33
        if self.FORCE_FULL_DISPLAY or self.context['view'].action != 'list':
34
35
36
37
38
39
            versions = Version.objects.get_for_object(obj)
            return len(versions)
        return None

    def get_content_type_id(self, obj):
        return ContentType.objects.get_for_model(self.Meta.model).id
Florent Chehab's avatar
Florent Chehab committed
40

Florent Chehab's avatar
Florent Chehab committed
41
    def save(self, *args, **kwargs):
Florent Chehab's avatar
Florent Chehab committed
42
        with reversion.create_revision():
Florent Chehab's avatar
Florent Chehab committed
43
            res = self.my_save(*args, **kwargs)
Florent Chehab's avatar
Florent Chehab committed
44
            reversion.set_user(res.updated_by)
Florent Chehab's avatar
Florent Chehab committed
45
        new_revision_saved.send(sender=self.__class__, obj=self.instance)
46
        return res
Florent Chehab's avatar
Florent Chehab committed
47
48
49
50


class MyModelVersionnedViewSet(MyModelViewSet):
    serializer_class = MyModelVersionnedSerializer
51
52


Florent Chehab's avatar
Florent Chehab committed
53
class VersionSerializer(MySerializerWithJSON):
54
55
56
    data = serializers.SerializerMethodField()

    def get_data(self, obj):
Florent Chehab's avatar
Florent Chehab committed
57
58
59
        """
        TODO test
        """
60
61
62
63
64
65
66
        data = obj.serialized_data

        try:
            tmp = list(djangoSerializers.deserialize(
                obj.format, data, ignorenonexistent=True))[0]
            # Version is valid,
            obj_serializer = tmp.object.get_serializer()
Florent Chehab's avatar
Florent Chehab committed
67
68
69
            new_context = dict(self.context)
            new_context['view'].action = 'list'
            return obj_serializer(tmp.object, context=new_context).data
70
71
72
73
74
75
76
77
78
79
80
81
        except (DeserializationError, djangoSerializers.SerializerDoesNotExist):
            obj.delete()  # The version is not valid regarding the model, we should delete it !
            # Might result in inconsistent nb of versions but that's fine.
            return None

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


class VersionViewSet(mixins.ListModelMixin,
                     viewsets.GenericViewSet):  # TODO better presentation
82
    permission_classes = get_viewset_permissions("VersionViewSet")
83
84
85
86
87
88
89
90
91
    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)