【问题标题】:create() argument after ** must be a mapping, not list, Django REST Framework (implementing my own create method error)**后的create()参数必须是映射,不是列表,Django REST Framework(实现我自己的create方法报错)
【发布时间】:2018-11-21 18:02:51
【问题描述】:

当我在文档上实现这个代码示例时(我必须自己实现 create 方法,因为我有嵌套对象并且默认不支持插入它们)

def create(self, validated_data):
    profile_data = validated_data.pop('profile')
    user = User.objects.create(**validated_data)
    Profile.objects.create(user=user, **profile_data)
    return user

https://www.django-rest-framework.org/api-guide/serializers/#writing-create-methods-for-nested-representations

我收到了这个错误

create() argument after ** must be a mapping, not list

我在项目中的示例实现如下:

def create(self, validated_data):
    product_data = validated_data.pop('categories')
    product = Product.objects.create(**validated_data)
    Product.objects.create(product=product, **product_data)
    return product

整个 serializers.py 文件

from rest_framework import serializers
from products_and_categories.models import Product, Category
from django.db import models


class CategorySerializer(serializers.ModelSerializer):
    def to_representation(self, obj):
        if 'categories' not in self.fields:
            self.fields['categories'] = CategorySerializer(obj, many=True)      
        return super(CategorySerializer, self).to_representation(obj)

    class Meta:
        model = Category
        fields = ("name", 'products', 'categories')

class ProductSerializer(serializers.ModelSerializer):
    categories = CategorySerializer(many=True)
    class Meta:
        model = Product
        fields = ("product_code", "name", "quantity", "price", 'categories')

    def create(self, validated_data):
        product_data = validated_data.pop('categories')
        product = Product.objects.create(**validated_data)
        Product.objects.create(product=product, **product_data)
        return product

我的 models.py 文件:

from django.db import models

# Create your models here.

class Category(models.Model):
    name = models.CharField(max_length=255)
    categoriesId = models.ForeignKey('self', related_name='categories',on_delete=models.CASCADE, blank=True, null=True)

class Product(models.Model):
    product_code = models.CharField(max_length=255)
    name = models.CharField(max_length=255)
    price = models.IntegerField()
    quantity = models.IntegerField()
    categories = models.ManyToManyField(Category, related_name='products')

谁能帮我找出问题所在?

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    您在这里混淆了各种名称。您从validated_data 中弹出categories 元素,并将其分配给product_data;但它不是产品数据,而是类别列表。

    然后您尝试使用与现有产品相关的数据创建产品 - 大概您打算在那里创建一个类别。但同样,您拥有的是一个 list,因此您需要遍历并为每个条目创建一个类别。

    最后请注意,产品和类别之间存在多对多关系,而不是示例中的外键,因此您不能使用 product=product 语法。

    这样会更好:

    def create(self, validated_data):
        category_data = validated_data.pop('categories')
        product = Product.objects.create(**validated_data)
        for category in category_data:
            product.categories.create(**category)
        return product
    

    (虽然请注意,是的,DRF 支持创建嵌套项;请参阅serializer relations 上的文档。)

    【讨论】:

    • 非常感谢,虽然在尝试了你的方式之后,我收到了一条错误消息 Direct assignment to the reverse side of a many-to-many set is prohibited. Use products.set() instead.,当我使用 product.categories.set(**category_data) 时,我得到了 set() got an unexpected keyword argument 'name'
    • 知道那是什么吗?
    • 此代码不会给出该错误。你能用你使用的确切代码更新你的问题吗?
    • 你的意思是category 是category_data 在product.categories.create(**category_data) 中,对吧?因为否则它会再次给出create() argument after ** must be a mapping, not list 错误
    • 我只是假设您的意思是 **category 而不是 **category_data
    【解决方案2】:

    所以我会添加这个答案,以防你像我一样是个傻瓜。

    我之前有与此工作类似的代码,并对我从中获取 JSON 的 Flask 应用程序的端点进行了一些更改。

    我添加的其中一个更改是在字典中添加了一个 count 项,这样我就可以轻松地查看我正在迭代多少项。

    所以很明显,当我根据这个 JSON 数据在 Django 中保存每个模型实例时,第一项有一个整数值作为计数,这显然是行不通的。

    【讨论】:

      猜你喜欢
      • 2021-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-16
      • 1970-01-01
      • 2016-05-02
      • 1970-01-01
      相关资源
      最近更新 更多