I'm using django-simple-history to track model changes.
It's easy enough to get all history records for a model class or a model instance:
poll = Poll.objects.create(question="what's up?", pub_date=datetime.now())
poll.history.all()
# and
Choice.history.all()
But what I'm looking to do is to have endpoints like /history/model
and /history/model/1
that returns paginated history records for either the class or class instance.
Now I've already got Django REST Framework (DRF) set up with pagination, and have all my views paginated, something like:
class MyModelViewSet(viewsets.ModelViewSet):
serializer_class = MyModelSerializer
permission_classes = [permissions.IsAuthenticated]
queryset = MyModel.objects.all()
class MyModelSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = MyModel
fields = ["name"]
class MyModel(models.Model):
name = models.CharField(max_length=100, unique=True)
That all works fine.
How can I paginate the django-simple-history
records?
Can I create a simple history serializer? Because there's not exactly a simple history model I can use (I think).
I am going to use the Poll model for this example and I have created an app called polls.
class Poll(models.Model):
question = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published', auto_now_add=True)
history = HistoricalRecords()
After you migrate a new table is created call 'polls_historicalpoll'. You can use inspectdb command to create a model for this or simple created manually by looking at the field in the database. For example.
class HistoricalPoll(models.Model):
id = models.BigIntegerField()
question = models.CharField(max_length=200)
pub_date = models.DateTimeField()
history_id = models.AutoField(primary_key=True)
history_date = models.DateTimeField()
history_change_reason = models.CharField(max_length=100, blank=True, null=True)
history_type = models.CharField(max_length=1)
history_user = models.ForeignKey(get_user_model(), models.DO_NOTHING, blank=True, null=True)
class Meta:
managed = False
db_table = 'polls_historicalpoll'
Now you can create a serializer for this model:
#serializers.py
from rest_framework import serializers
from .models import HistoricalPoll
class HistoricalPollSerializer(serializers.ModelSerializer):
class Meta:
model = HistoricalPoll
fields = '__all__'
Now that you have the serializer you can create a ModelViewset. To make things simple I have overwriten the get_queryset methode to filter by poll id but you can also use djangofilterbackend see https://www.django-rest-framework.org/api-guide/filtering/#djangofilterbackend
#views.py
from rest_framework import viewsets, permissions
from polls.models import HistoricalPoll
from polls.serializers import HistoricalPollSerializer
class HistoricalPollViewSet(viewsets.ModelViewSet):
serializer_class = HistoricalPollSerializer
permission_classes = [permissions.IsAuthenticated]
queryset = HistoricalPoll.objects.all()
def get_queryset(self):
poll_id = self.request.GET.get('poll_id')
return HistoricalPoll.objects.filter(id=poll_id)
Depending on your urls you can access all the history of polls like this: http://127.0.0.1:8000/api/v1/polls/historical_polls
Or you can filter by poll id like this: http://127.0.0.1:8000/api/v1/polls/historical_polls?poll_id=3
This worked perfectly for me. Let me know if it helps you.