Friday, April 13, 2018

How to POST Model with Many to Many through in Django REST

Leave a Comment

I have a model with a many to many connection. I would like to make this model available in Django REST. By default such a model is read only, but I would also like to write. Furthermore, it would be great to get the information of the through connection integrated into the GET as a nested model.

... class KeyDateCase(models.Model):     ...     diagnoses_all_icd_10 = models.ManyToManyField(         'ICD10', through='CaseICD10Connection') ...  class CaseICD10Connection(models.Model):     case = models.ForeignKey('KeyDateCase', on_delete=models.CASCADE)     icd_10 = models.ForeignKey('ICD10', on_delete=models.CASCADE)     is_primary = models.BooleanField(default = False)     certainty = models.CharField(         max_length=1,         choices=CERTAINTY_CHOICES,         default='G',     )  class ICD10(models.Model):      primary_key_number = models.CharField(max_length=10, primary_key=True)      star_key_number = models.CharField(max_length=10, blank=True, null=True)      additional_key_number = models.CharField(         max_length=10, blank=True, null=True)      preferred_short_description = models.CharField(max_length=128, ) ...  class KeyDateCaseViewSet(viewsets.ModelViewSet):     ???  class KeyDateCaseSerializer(serializers.ModelSerializer):     ??? 

How can I achieve this? What should my view and serializer look like?

2 Answers

Answers 1

Normally I workaround by indirect way by POST to through table and implement nested-create(). Please provide me more information if my answer is inaccurate.

models.py

from django.db import models   class ICD10(models.Model):     primary_key_number = models.CharField(max_length=10, primary_key=True)     star_key_number = models.CharField(max_length=10, blank=True, null=True)     additional_key_number = models.CharField(max_length=10, blank=True, null=True)     preferred_short_description = models.CharField(max_length=128, )      def __str__(self):         return f'{self.primary_key_number} {self.star_key_number}'   class CaseICD10Connection(models.Model):     case = models.ForeignKey('KeyDateCase', related_name='connections', related_query_name='key_date_cases', on_delete=models.CASCADE)     icd_10 = models.ForeignKey('ICD10', related_name='connections', related_query_name='icd_10s', on_delete=models.CASCADE)     is_primary = models.BooleanField(default=False)     certainty = models.CharField(max_length=1, default='G', )   class KeyDateCase(models.Model):     name = models.CharField(max_length=20)     diagnose_all_icd_10 = models.ManyToManyField(ICD10, related_name='icd10s', related_query_name='icd10s',                                                  through=CaseICD10Connection) 

serializers.py

from rest_framework import serializers  from keydatecases.models import KeyDateCase, ICD10, CaseICD10Connection   class KeyDateCaseSerializer(serializers.ModelSerializer):     class Meta:         model = KeyDateCase         fields = [             'id',             'name',             'diagnose_all_icd_10',         ]         read_only_fields = ['id', 'diagnose_all_icd_10']   class ICD10Serializer(serializers.ModelSerializer):     class Meta:         model = ICD10         fields = [             'primary_key_number',             'star_key_number',             'additional_key_number',             'preferred_short_description',         ]   class CaseICD10ConnectionSerializer(serializers.ModelSerializer):     case = KeyDateCaseSerializer()     icd_10 = ICD10Serializer()      class Meta:         model = CaseICD10Connection         fields = [             'case',             'icd_10',             'is_primary',             'certainty',         ]      def create(self, validated_data) -> CaseICD10Connection:         # import ipdb;         # ipdb.set_trace()         # create key_date_case         key_date_case = KeyDateCase.objects.create(**validated_data.get('case'))          # create icd10         icd10 = ICD10.objects.create(**validated_data.get('icd_10'))          # create connection         conn = CaseICD10Connection.objects.create(             case=key_date_case, icd_10=icd10, is_primary=validated_data.get('is_primary'),             certainty=validated_data.get('certainty')         )         return conn 

viewsets.py

from rest_framework import viewsets  from keydatecases.api.serializers import CaseICD10ConnectionSerializer from keydatecases.models import CaseICD10Connection   class CaseICD10ConnectionViewSet(viewsets.ModelViewSet):     permission_classes = ()     queryset = CaseICD10Connection.objects.all()     serializer_class = CaseICD10ConnectionSerializer 

My Repository:
I share my repository with many questions. Please do not mind it.
https://github.com/elcolie/tryDj2

Answers 2

In regards to creating or updating nested objects, the documentation actually has a great example. I would provide you a better one if I could. If there is anything confusing in the example, happy to explain it here.

If you follow this approach, your GET requests will expand the nested objects automatically for you.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment