'Getting rest history from Django simple History

I am using django-simple-history (1.8.1) and DRF (3.5.3). I want to get a rest service containing the history of each element. Let's take an example !

models.py

class Product(models.Model):
    name = models.CharField(max_length=50)
    price = models.IntegerField()
    history = HistoricalRecords()

    def __str__(self):
        return self.name

So, what must be serializers.py ? I'd like to GET something like :

[
    {
        "id": 1,
        "name": "Apple",
        "price": 8,
        "history": [
            {
                "history_id": 1,
                "id": 1,
                "name": "Apple",
                "price": 0,
                "history_date": "2016-11-22T08:02:08.739134Z",
                "history_type": "+",
                "history_user": 1
            },
            {
                "history_id": 2,
                "id": 1,
                "name": "Apple",
                "price": 10,
                "history_date": "2016-11-22T08:03:50.845634Z",
                "history_type": "~",
                "history_user": 1
            },
            {
                "history_id": 3,
                "id": 1,
                "name": "Apple",
                "price": 8,
                "history_date": "2016-11-22T08:03:58.243843Z",
                "history_type": "~",
                "history_user": 1
            }
        ]
    }
]

After searching whitout finding the solution, I finally found it by myself. But if someone have a better solution...



Solution 1:[1]

I know it's been a year, but anyway, maybe someone finds it useful. Here is my solution (it seems far easier to me):

A new serializer field:

class HistoricalRecordField(serializers.ListField):
    child = serializers.DictField()

    def to_representation(self, data):
        return super().to_representation(data.values())

Now simply use it as a a field in your serializer:

history = HistoricalRecordField(read_only=True)

This makes use of DRF's built in list and dict serializers, only trick is to pass it the correct iterable, which is being done by calling .values() on the simple-history model manager class.

Solution 2:[2]

Here's my solution. In serializers.py :

from rest_framework import serializers
from .models import Product


class sHistory(serializers.ModelSerializer):
    def __init__(self, model, *args, fields='__all__', **kwargs):
        self.Meta.model = model
        self.Meta.fields = fields
        super().__init__()

    class Meta:
        pass


class sProduct(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = '__all__'

    history = serializers.SerializerMethodField()

    def get_history(self, obj):
        model = obj.history.__dict__['model']
        fields = ['history_id', ]
        serializer = sHistory(model, obj.history.all().order_by('history_date'), fields=fields, many=True)
        serializer.is_valid()
        return serializer.data

It works ! I'm quite proud about it ! any suggestions ?

Solution 3:[3]

There seems to be an even clearer and simpler way

class AnySerializer(serializers.ModelSerializer):    
    history = serializers.SerializerMethodField()

    class Meta:
        model = MyModel
        fields = (....
                  ....
                  'history',
                  )
        read_only_fields = ('history',)

    def get_history(self, obj):
        # using slicing to exclude current field values
        h = obj.history.all().values('field_name')[1:]
        return h

Solution 4:[4]

You can create a serializer like this:

class ProductHistorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Product.history.model
        fields = '__all__'

Then in view, You can have the code below:

#...
logs = ProductHistorySerializer(Product.history.filter(price__gt=100), many=True)
return Response({'isSuccess': True, 'data': logs.data})

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 wizpig64
Solution 2
Solution 3 Jekson
Solution 4 Ehsan Ahmadi