【问题标题】:Django Rest Framework | Writable multiple nested relationsDjango 休息框架 |可写多重嵌套关系
【发布时间】:2019-08-06 20:58:35
【问题描述】:

我有一些模型,它们相互嵌套。我想为 2 个序列化程序进行批量创建,它们都与其他模型有关系。我查看了DRF 上的文档,但无法在我的代码中实现它。

我这样发送我的 json 数据:

{
  'status':true,
  'products':[
              {
               'painting':{'amount':10}, 
               'product':{'id':12, }
              },
              {
               'painting':{'amount':10}, 
               'product':{'id':12, }
              }
             ],
   'customer':{ 'name':'Adnan',
                'address':{'country':'Turkey'}
              },
    'total':111

}

#models.py

class Address():
    ...
class Customer():
    address = models.ForeignKey(Address, ...)
class Painting():
    ...
class Product():
    ...
class Selling():
    customer = models.ForeignKey(Customer, ...)
    products = models.ManyToManyField(Product, through='SellingProduct')
class SellingProduct():
    selling = models.ForeignKey(Selling, ...)
    product = models.ForeignKey(Product, ...)
    painting = models.ForeignKey(Painting, ...)

这是我的serializers.py

class AddressSerializer():
    ...
class CustomerSerializer():
    address = AddressSerializer()
    ...
class PaintingSerializer():
    ...
class ProductSerializer():
    ...
class SellingProductSerializer():
    painting = PaintingSerializer()
    product = ProductSerializer()

class SellingSerializer():
    customer = CustomerSerializer()
    products = SellingProductSerializer(many=True)
    ...
    def create(self, validated_data):
        ...

如果我这样写:

class SellingSerializer():
    ...
    def create(self, validated_data):
        customer_data = validated_data.pop('customer')
        products_data = validated_data.pop('products')
        selling = Selling.objects.create(**validated_data) #i didn't pass customer here
        for product_data in products_data:
            SellingProducts.objects.create(selling=selling, **product_data)
        return selling

我收到此错误:

django.db.utils.IntegrityError: (1048, "Column 'customer_id' cannot be null")

如果我这样写:

class SellingSerializer():
    ...
    def create(self, validated_data):        
        selling = Selling.objects.create(**validated_data) #i didn't pass customer here        
        return selling

我收到此错误:

ValueError: Cannot assign "OrderedDict...
..Selling.customer must be a "Customer" instance
  • 如果数据类型是 OrderedDict,我不知道如何提取或访问数据。我该怎么做呢?

我想为 Selling 和 SellingProduct、Painting 创建一条记录,我不想在每个请求中创建 Customer、Address、Product 记录,我将使用存在(在前端选择的)数据。

提前感谢大家的帮助!

【问题讨论】:

  • 您能更具体地说明您遇到的问题吗?根据 DRF 文档,您应该能够解压缩 create() 中的值并直接持久化实例
  • @MatthewHegarty 我编辑了它。

标签: python django django-rest-framework


【解决方案1】:

如果您进行一些修改,您的第一种方法应该会奏效。您的销售模型依赖于客户,因此您首先需要创建一个客户。然后,您的 SellingProduct 模型依赖于产品和绘画,因此您首先需要创建一个产品和绘画,然后使用这些实例创建一个 SellingProduct,如下所示:

class SellingSerializer():
    ...
    def create(self, validated_data):
        customer_data = validated_data.pop('customer')
        selling_products_data = validated_data.pop('products')

        customer = Customer.objects.create(**customer_data)
        selling = Selling.objects.create(customer=customer, **validated_data)

        for selling_product_data in selling_products_data :
            product_data = selling_product_data.pop('product')
            product = Product.objects.create(**product_data)

            painting_data = selling_product_data.pop('painting')
            painting = Painting.objects.create(**painting_data)

            SellingProducts.objects.create(selling=selling, product=product, painting=painting)

        return selling

当然,这种方法会为每个请求创建一个新的客户、产品和绘画。这真的是你想要的吗?如果您不想为每个请求创建新的 Product 和 Painting 实例,而是使用对现有实例的引用,您可以将它们定义为 SellingSerializer 和 SellingProductSerializer 中的 PrimaryKeyRelatedField 字段。然后,您可以将您的创建功能更改为:

def create(self, validated_data):
    customer = validated_data.pop('customer')
    selling_products_data = validated_data.pop('products')

    selling = Selling.objects.create(customer=customer, **validated_data)

    for selling_product_data in selling_products_data :
        SellingProducts.objects.create(selling=selling, **selling_product_data )

    return selling

【讨论】:

    【解决方案2】:

    您需要先使用CustomerSerializer 创建客户对象和数据库行,然后才能创建带有外键的Selling 对象。您正在尝试不传递任何内容或正在传递 JSON(在您的错误消息中变成 OrderedDict)。

    class SellingSerializer():
        ...
        def create(self, validated_data):
            customer_data = validated_data.pop('customer')
            products_data = validated_data.pop('products')
            customer = CustomerSerializer.save(**customer_data)
            selling = Selling.objects.create(customer=customer, **validated_data)
            for product_data in products_data:
                SellingProducts.objects.create(selling=selling, **product_data)
            return selling
    

    也许在这个问题上重新阅读documentation

    【讨论】:

      【解决方案3】:
      1. SellingSerializer 与 CustomerSerializerh、ProductSerializer 相关

      2. 在创建 Selling 对象之前,我们可以验证每个序列化器并创建

      3. 更新验证数据

      4. 多对多进程

      您不会只是创建客户对象产品对象。必须验证数据并且可以使用 CustomerSerializer 和 ProductSerializer。在创建它们之前,使用 CustomerSerializer 和 ProductSerializer 序列化您的数据,然后是有效的创建对象,否则会引发异常。

      class SellingSerializer():
          ...
      
          def create(self, validated_data):
              # First Let's handle Customer data
              customer_data = validated_data.pop('customer')
              customer_serializer = CustomerSerializer(data=customer_data)
              customer_serializer.is_valid(raise_exception=True)
              customer = customer_serializer.save()
              validated_data.update({'customer':customer})  ## update our validated data with customer instance
      
              # Create Selling object
              selling = Selling.objects.create(**validated_data)  # will receive customer instance as well
      
              # Handle Products related Data
              products_data = validated_data.pop('products')
              for product_data in products_data:
                  product_serializer = ProductSerializer(data=product_data)
                  product_serializer.is_valid(raise_exception=True)
                  product = product_serializer.save()
                  SellingProducts.objects.create(selling=selling, product=product)
      
              return selling
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-09-11
        • 1970-01-01
        • 2013-06-13
        • 2014-09-18
        • 1970-01-01
        • 1970-01-01
        • 2017-06-28
        相关资源
        最近更新 更多