I'm attempting to build a nested relationship using Django Rest Framework 3.0. I've created my serializers and have attempted to override the create()
function. My models are defined as follows:
class Item(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
name = models.CharField(max_length=200)
description = models.CharField(max_length=1000)
categories = models.ManyToManyField(Category, null=True, blank=True)
class Price(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
item = models.ForeignKey(Item, related_name='prices')
name = models.CharField(max_length=100)
cost = models.FloatField()
As you'll note, I can have multiple prices for my items. My serializers are defined as follows:
class PriceSerializer(serializers.ModelSerializer):
class Meta:
model = Price
owner = serializers.Field(source='owner.username')
exclude = ('user',)
class ItemSerializer(serializers.ModelSerializer):
prices = PriceSerializer(many=True, required=False)
categories = CategorySerializer(many=True, required=False)
class Meta:
model = Item
owner = serializers.Field(source='owner.username')
fields = ('id', 'name', 'description', 'prices', 'categories')
def create(self, validated_data):
user = validated_data.get('user')
# Get our categories
category_data = validated_data.pop('categories')
# Create our item
item = Item.objects.create(**validated_data)
# Process the categories. We create any new categories, or return the ID of existing
# categories.
for category in category_data:
category['name'] = category['name'].title()
category, created = Category.objects.get_or_create(user=user, **category)
item.categories.add(category.id)
item.save()
return item
When I try and POST a new item:
{
"name": "Testing",
"description": "This is a test",
"categories": [
{
"name": "foo"
},
{
"name": "bar"
}
],
"prices": [
{
"name": "Red",
"cost": 10
}
]
}
I get the following error:
{
"prices": [
{
"item": [
"This field is required."
]
}
]
}
Presumably because the Price serializer has no idea what the ID of the new item is. I've tried overriding this functionality in the create()
function of my serializer, but it appears as though the serializer's validation is being hit before I have the opportunity to create the item and associate it with the price.
So - How do I create a new item, get the item ID, and then create each of the new prices?
The problem is that your PriceSerializer
is looking for the item
key because it is specified on the Price
model. This isn't immediately obvious because you are using Meta.exclude
instead of Meta.fields
.
class PriceSerializer(serializers.ModelSerializer):
class Meta:
model = Price
exclude = ('user',)
Is the same as writing
class PriceSerializer(serializers.ModelSerializer):
class Meta:
model = Price
fields = ('id', 'item', 'name', 'cost', )
Which makes it very clear what your issue is. Because your item
field on the model does not have empty=True
(or null=True
) set, Django REST Framework automatically generates it as a PrimaryKeyRelatedField
with required=True
. This is why you are getting the This field is required
is required error, because Django REST Framework cannot automatically detect that it is coming from a parent serializer which already has that field.
You can get around this by removing the field from the serializer, as it doesn't appear to ever be needed.
class PriceSerializer(serializers.ModelSerializer):
class Meta:
model = Price
fields = ('id', 'name', 'cost', )
This will no longer display the item
field though, but I suspect this isn't actually an issue for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With