Reputation: 471
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:
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!
Upvotes: 2
Views: 1415
Reputation: 14391
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
Upvotes: 2