Serialising many related models

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

DRF is capable of handling this for you – the Serializer relations guide page should get you started nicely.

Cheers Rixx,

I worked this one out today from the docs with the help of related_names

question = models.ForeignKey(Question, related_name='answers', on_delete=models.CASCADE)

and of course, ModelSerializers

class QuestionSerializer(serializers.ModelSerializer):
    answers = AnswerSerializer(many=True, read_only=True)

Clever Django devs think of everything!

Cheers,

C