I'm using django-simple-history==3.2.0 library and my models show below:
class Employee(models.Model):
last_name: str | None = models.CharField(max_length=100, null=True) # type: ignore
first_name: str | None = models.CharField(max_length=100, null=True) # type: ignore
middle_name: str | None = models.CharField(max_length=100, null=True) # type: ignore
job_title: str | None = models.CharField(max_length=512, null=True) # type: ignore
class Meta:
app_label = "task_flow"
class Assignment(models.Model):
overdue: int = models.IntegerField(null=True) # type: ignore
# ManyToManyField
executors: QuerySet[Employee] = models.ManyToManyField(Employee, related_name="executor_assignments", blank=True) # type: ignore
coordinators: QuerySet[Employee] = models.ManyToManyField(Employee, related_name="coordinator_assignments", blank=True) # type: ignore
approvers: QuerySet[Employee] = models.ManyToManyField(Employee, related_name="approver_assignments", blank=True) # type: ignore
# ForeignKey
status: Status | None = models.ForeignKey(Status, on_delete=RESTRICT, related_name="assignments") # type: ignore
access: Access = models.ForeignKey(Access, on_delete=RESTRICT, related_name="assignments", default=Access.Choices.general, null=True, blank=False) # type: ignore
document_type: DocumentType | None = models.ForeignKey(DocumentType, on_delete=SET_NULL, null=True, related_name="assignments") # type: ignore
domain: Domain = models.ForeignKey(Domain, on_delete=RESTRICT, null=False, related_name="assignments", default=Domain.Choices.internal) # type: ignore
source: str | None = models.CharField(max_length=2048, null=True, blank=True) # type: ignore
created_at: datetime = models.DateTimeField(auto_now_add=True) # type: ignore
updated_at: datetime = models.DateTimeField(auto_now=True) # type: ignore
history = HistoricalRecords(m2m_fields=[executors, coordinators, approvers])
So, now i want to serializer Assignment.history.all() queryset with employees all fields like this:
"results": [
{
"id": 551,
"overdue": 243,
"executors": [
{
"id": 32,
"last_name": "Копытов",
"first_name": "О.",
"middle_name": "В.",
"job_title": "Генеральный директор ТОО \"Корпорация Казахмыс\"",
"user": 470,
"domain": 1
},
...
}
]
When I try to get instance.approvers.all() in returns me list of task_flow_historicalassignment_approvers table instances, not emplyees.
I resolved this issue by writing serializer class with custom to_representation method:
class AssignmentHistorySerializer(AssignmentTableSerializer):
history_user = UserLogsSerializer(many=False)
history_type = serializers.CharField()
def to_representation(self, instance):
rep = super().to_representation(instance)
approvers = Employee.objects.filter(id__in=instance.approvers.all().values_list('employee_id', flat=True))
coordinators = Employee.objects.filter(id__in=instance.coordinators.all().values_list('employee_id', flat=True))
executors = Employee.objects.filter(id__in=instance.executors.all().values_list('employee_id', flat=True))
rep['approvers'] = EmployeeSerializer(approvers, many=True).data
rep['coordinators'] = EmployeeSerializer(coordinators, many=True).data
rep['executors'] = EmployeeSerializer(executors, many=True).data
rep['history_date'] = instance.history_date
rep['history_user'] = UserLogsSerializer(instance.history_user).data
rep['history_type'] = instance.get_history_type_display() # Assuming there's a method to get a displayable type.
rep['changed_fields'] = self.changed_fields(instance)
rep['history_id'] = instance.history_id
return rep
def changed_fields(self, obj):
if obj.prev_record:
delta = obj.diff_against(obj.prev_record, excluded_fields=['updated_at', 'created_at', 'overdue', 'search_field'])
return delta.changed_fields
return None