Django Rest Framework 3.0:保存嵌套,多对一关系

Jul*_*lio 8 python django serialization django-rest-framework

我正在尝试使用Django Rest Framework 3.0构建嵌套关系.我已经创建了序列化程序并试图覆盖该create()函数.我的模型定义如下:

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()
Run Code Online (Sandbox Code Playgroud)

正如您将注意到的,我可以为我的商品设置多个价格.我的序列化器定义如下:

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
Run Code Online (Sandbox Code Playgroud)

当我尝试POST一个新项目时:

{
    "name": "Testing",
    "description": "This is a test",
    "categories": [
        {
            "name": "foo"
        },
        {
            "name": "bar"
        }
    ],
    "prices": [
        {
            "name": "Red",
            "cost": 10
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

{
    "prices": [
        {
            "item": [
                "This field is required."
            ]
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

大概是因为Price序列化器不知道新项目的ID是什么.我已经尝试在create()我的序列化程序的功能中覆盖此功能,但在我有机会创建项目并将其与价格相关联之前,似乎序列化程序的验证正在被击中.

那么 - 如何创建新项目,获取项目ID,然后创建每个新价格?

Kev*_*own 5

问题是您PriceSerializer正在寻找item密钥,因为它是在Price模型上指定的.这并不是很明显,因为你使用的是Meta.exclude代替Meta.fields.

class PriceSerializer(serializers.ModelSerializer):

    class Meta:
        model = Price
        exclude = ('user',)
Run Code Online (Sandbox Code Playgroud)

和写作一样

class PriceSerializer(serializers.ModelSerializer):

    class Meta:
        model = Price
        fields = ('id', 'item', 'name', 'cost', )
Run Code Online (Sandbox Code Playgroud)

这使得您的问题非常清楚.因为item模型上的字段没有empty=True(或null=True)设置,Django REST Framework会自动将其生成为PrimaryKeyRelatedField with required=True.这就是你得到This field is required必需错误的原因,因为Django REST Framework无法自动检测到它来自已经拥有该字段的父序列化程序.

你可以通过从序列化器中删除字段来解决这个问题,因为它似乎不需要.

class PriceSerializer(serializers.ModelSerializer):

    class Meta:
        model = Price
        fields = ('id', 'name', 'cost', )
Run Code Online (Sandbox Code Playgroud)

这将不再显示该item字段,但我怀疑这对您来说实际上不是问题.