2

I am trying to work with Django rest framework in conjunction with Django simple history. This answer has gotten me pretty far with understanding how to serialize the history items of a model. This works well for simple cases, but my model has a calculated field ("store" in the example below). The problem is that the the serialization of the history field doesn't seem to capture these. How to I serialize the history in the same way as the main model? Is it possible to do this in the to_representation method of the HistoricalRecordField?

class MyModel(models.Model):
    ...
    history = HistoricalRecords()

    @property
    def store(self):
          return {}



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

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



class MySerializer(serializers.ModelSerializer):
    ...
    store = serializers.DictField(child=serializers.CharField(), read_only=True)
    history = HistoricalRecordField(read_only=True)
  
    class Meta:
        model = MyModel

What I get is something like:

[
    {
        "id": 1,
        "store": {} 
        "history": [
            {
                "history_id": 1,
                "id": 1,
                "history_date": "2016-11-22T08:02:08.739134Z",
                "history_type": "+",
                "history_user": 1
            },
            {
                "history_id": 2,
                "id": 1,
                "history_date": "2016-11-22T08:03:50.845634Z",
                "history_type": "~",
                "history_user": 1
            }
        ]
    }
]

But what I want are the history items without the history columns and with the "store" field which doesn't show up. Basically I'd like the list of history items to be serialized like they were items from the main model:

[
    {
        "id": 1,
        "store": {...} ,
        ...
        "history": [
            {
                "store": {...},
                ...
                "id": 1,
            },
            {
                "store": {...},
                ...
                "id": 1,
            }
        ]
    }
]
cts
  • 1,790
  • 1
  • 13
  • 27
  • 1
    What output do you get for history when you try to use `MySerializer`? Errors? Also can you share the fields you have specified in `MySerializer.Meta` – Brian Destura Jul 20 '21 at 03:54
  • There are no errors. history in MySerializer returns a list of dictionaries where each key is from the history table - basically what you would see from the linked answer. I don't have any fields explicitly specified in MySerializer besides store and history and nothing specified in MySerializer.Meta – cts Jul 20 '21 at 05:14
  • Doesn't that mean it's working fine? If not, can you share exactly what you are expecting to get and what you are actually getting? It would help to put a sample serialized data in the question. Apologies if I'm misunderstanding – Brian Destura Jul 20 '21 at 05:18
  • I added in my expected output. It's not quite getting me what I want as the history items have all of the additional fields from the HistoricalRecords class and the fields that don't come from the main model's table (like store) aren't present. I think what I basically want is to cast the HistoricalRecords back into the main model and then serialize that. But don't understand how to do it. – cts Jul 20 '21 at 05:42
  • Thanks for the update. It's very clear now. This problem is because `store` is a property and not a field.. Tricky – Brian Destura Jul 20 '21 at 05:43

1 Answers1

0

The solution that I found was to create a separate serializer for the historical records that acted the same way as the main serializer. Then use that serializer in the to_representation method of HistoricalRecordfield. Note that you can't use the main serializer (MySerializer) as it creates recursion.

class HistoricalSerializer(serializers.ModelSerializer):
    ...
    store = serializers.DictField(child=serializers.CharField(), read_only=True)

    class Meta:
        model = MyModel

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

    def to_representation(self, data):
        dvs = HistoricalRecordSerializer(data, many=True).data
        return super().to_representation(dvs)
cts
  • 1,790
  • 1
  • 13
  • 27