2

I'm new to DRF (and Django) and trying to create a nested serializer which is able to validate the following request data:

{
    "code": "12345",
    "city": {
        "name": "atlanta",
        "state": "Georgia"
    },
    "subregion": {
        "name": "otp north"
    }
}

To simplify things for the client, I'd like this single request to create multiple records in the database:

  • A City (if a matching one doesn't already exist)
  • A Subregion (if a matching one doesn't already exist)
  • A CodeLog which references a city and (optionally) a subregion

Models:

class City(models.Model):
    name = models.CharField(max_length=75, unique=True)
    state = models.CharField(max_length=50, blank=True)

class Subregion(models.Model):
    city = models.ForeignKey(City)
    name = models.CharField(max_length=75)

class CodeLog(models.Model):
    code = models.CharField(max_length=10)
    city = models.ForeignKey(City)
    subregion = models.ForeignKey(Subregion, blank=True, null=True)

Serializers:

class CitySerializer(serializers.ModelSerializer):
    class Meta:
        model = City
        fields = ('name', 'state')

class SubregionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Subregion
        fields = ('name',)

class CodeLogSerializer(serializers.ModelSerializer):
    city = CitySerializer()
    subregion = SubregionSerializer(required=False)

    class Meta:
        model = CodeLog
        fields = ('code', 'city', 'subregion')

    # This is where I'm having troubles
    def create(self, validated_data):
        city_data = validated_data.pop('city', None)
        subregion_data = validated_data.pop('subregion', None)
        if city_data:
            city = City.objects.get_or_create(**city_data)[0]
        subregion = None
        if subregion_data:
            subregion = Subregion.objects.get_or_create(**subregion_data)[0]

        code_log = CodeLog(
            code=validated_data.get('code'),
            city=city,
            subregion=subregion
        )
        code_log.save()
        return code_log

View:

class CodeLogList(APIView):
    serializer_class = CodeLogSerializer

    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

I was able to get it working with a flat request structure, nested serializers are proving difficult to grasp. Am I on the right track, or is there a more ideal structure that would work better? Any help is greatly appreciated!

3
  • 2
    What is error you are getting? Commented Jan 29, 2018 at 5:37
  • null value in column "city_id" violates not-null constraint. I believe it's occurring because the subregion does not have a city (which is intended, as it should be getting this value from the created City instance). Commented Jan 29, 2018 at 16:19
  • Check my answer @cmasri. Commented Jan 29, 2018 at 17:49

1 Answer 1

2

Your Subregion model has a city field which is foreign key and cannot be null. Your create method should be like this.

def create(self, validated_data):
    city_data = validated_data.pop('city', None)
    subregion_data = validated_data.pop('subregion', None)
    if city_data:
        city = City.objects.get_or_create(**city_data)[0]
    subregion = None
    if subregion_data:
        # Add city in Subregion data
        subregion_data.update({'city': city})
        subregion = Subregion.objects.get_or_create(**subregion_data)[0]

    code_log = CodeLog(
        code=validated_data.get('code'),
        city=city,
        subregion=subregion
    )
    code_log.save()
    return code_log
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.