Hi All.
I’m using DRF to power my API and I am wonderfully happy with it. I do however have a function which I think I can improve. In short, I’m wanting to serialise a model and all models which may have it as a relation.
Let’s being with some models. First, I have a ‘Case’ model.
class Case(models.Model):
pass
Then, I have several models which have Case
as a foreign key.
class Treatment(models.Model):
case = models.Foreignkey(Case, on_delete=models.CASCADE)
class Quiz(models.Model):
case = models.Foreignkey(Case, on_delete=models.CASCADE)
class Diagnostics(models.Model):
case = models.Foreignkey(Case, on_delete=models.CASCADE)
And finally, I have some other models which reference Diagnostics
which in turn references Case
.
class Imaging(models.Model):
diagnostic = models.Foreignkey(Diagnostic, on_delete=models.CASCADE)
My front-end developer colleague has requested an API endpoint which returns an entire Case
. I.e., a Case record and every associated model and their records. There are in total 22 models which comprise a case.
To do this, I have built a dictionary by hand and return it. Here’s an abbreviated example from the get()
method of one of my CBVs that returns the entire Case
:
class EntireCaseView(APIView):
def get(self, request, pk):
# get the case and create the serialised object
case = self.get_object(int(pk))
case_serial = CaseSerializer(case, context={"request": request}
# get all treatments related to case
treatment = TreatmentSerializer(
Treatment.objects.all().filter(case=case),
context={"request": request},
many=True,
)
# diagnostic for case, which in turn have many models which reference diagnostic
diagnostic = DiagnosticSerializer(
Diagnostic.objects.all().filter(case=case),
context={"request": request},
many=True,
)
imaging = ImagingSerializer(
Imaging.objects.all().filter(diagnostic=diagnostic),
context={"request": request},
many=True,
)
# get all images related to Diagnostic for Case
imaging = ImagingSerializer(
Imaging.objects.all().filter(diagnostic=diagnostic),
context={"request": request},
many=True,
)
# start with the case dictionary
case_dict = case_serial.data
case_dict["treatment"] = treatment.data
case_dict["diagnostic"] = diagnostic.serial
case_dict["diagnostic"]["imaging"] = imaging.serial
return Response(case_dict)
Now, this works just fine, but I’m guessing there is a more elegant or perhaps more performant way to do it. Perhaps I can build my own customer serialiser or perhaps there is a way of using ModelSerialisers in such a way that I can use nested serializers. The thing which is tripping me up is that I need to get the Case ID, then fetch all its related models, and for those models which have other related models, get the ID and repeat. If my Case
model has had attributes for all its related models, then it would be simple, but that solution isn’t very scalable or dynamic.
Alright, that’s enough rambling for now. Any tips or ideas is, as always, much appreciated.
Cheers,
C