【问题标题】:How to POST a nested data and list of image如何发布嵌套数据和图像列表
【发布时间】:2017-09-28 19:44:05
【问题描述】:

有两种型号:ProductPicture。每个Product 可以有多个Pictures。当我想使用 POST 创建产品时,我有疑问。如何发布包含 ImageField 列表的嵌套对象?

Product 模型是:

class Product(models.Model):
    product_id = models.AutoField(primary_key=True)
    product_name = models.CharField(max_length=50)
    description = models.TextField(blank=True)

Picture 模型是:

class Picture(models.Model):
    product = models.ForeignKey(Product, related_name='pictures')
    path = models.ImageField(null=False, upload_to='product_pic')
    description = models.CharField(max_length=255, null=True, blank=True)
    main = models.BooleanField()

我编写 serializer.py 如下:

class PictureSerializer(serializers.ModelSerializer):
    class Meta:
        model = Picture
        fields = ('path', 'description', 'main')

class ProductSerializer(serializers.ModelSerializer): 
    pictures = PictureSerializer(many=True, required=False)

    class Meta:
        model = Product
        fields = ('product_id', 'product_name', 'pictures', 'description')

我使用的视图是:

class ProductEnum(generics.ListCreateAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    permission_classes = (IsAuthenticated, )

    def post(self, request, format=None):
        serializer = ProductSerializer(data=request.DATA, files=request.FILES)

        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)

我在网址中将其注册为:

url(r'^api/products/$', views.ProductEnum.as_view()),

问题是:

  • 我如何测试这个 POST api,因为 django-rest-framework 告诉我“HTML 输入中当前不支持列表”
  • 如何使用 JSON 发布具有多个 PicturesProduct 资源。或者我必须使用多部分解析器。
  • 如何编写 cURL 命令?

【问题讨论】:

  • 你做对了吗?

标签: json post curl django-rest-framework imagefield


【解决方案1】:

你必须使用多部分解析器,只要你需要发送二进制数据,你基本上只需要选择:

  1. 弱化你的 REST 方法并做一个例外 -> json 不能保存二进制数据
  2. 使用 base64 对每个二进制文件进行编码,保留 json 方法,但您需要为每个请求额外进行解码/编码(本机不支持)

一种经常看到的方法是创建一个(非休息)视图来上传单个/多个文件,这些文件创建 FileDocument 对象(在上传时返回一个 id)。然后您可以使用另一个请求的这些 ID,在您的情况下创建/更新您的 Product

一般来说,没有简单的方法可以做到这一点,因为 json 不支持二进制数据。

【讨论】:

    【解决方案2】:

    DRF 使这很容易做到。你很接近,你需要覆盖ProductSerializer.create,像这样:

    class ProductSerializer(serializers.ModelSerializer): 
        pictures = PictureSerializer(many=True, required=False)
    
        class Meta:
            model = Product
            fields = ('product_id', 'product_name', 'pictures', 'description')
    
        def create(self, validated_data):
            # Pop this from the validated_data first, since the serializer can't handle it.
            pictures = validated_data.pop('pictures')
            product = super().create(validated_data)
            # Now that we have a product to reference in the FKey, create the pictures.
            for picture in pictures:
                # `picture` has been run through the PictureSerialzer, so it's valid. 
                picture['product'] = product
                Picture.objects.create(**picture)
            return product
    

    文档中有一个完整的例子,这里:http://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers

    对于您的curl 命令,它将类似于:

    curl -X POST http://localhost:8000/products/ -H 'ContentType: application/json' -d '{"pictures": [{"description": "first one"}, {"description": "second one"}], "product_name": "foobar"}'

    【讨论】:

    • 您好,我按照您的做法做了,但没有用。请帮忙
    【解决方案3】:

    您可以使用 manage.py shell。 像这样:

    import requests
    r = requests.post("http://localhost:8000/login/url", data={"username": "username", "password": "password"}
    r.content (outputs token)
    token="yourtoken"
    r = requests.post("http://localhost:8000/your/url", data={your POST data in json}, headers={"Authorization": "Token %s" % token})
    

    【讨论】:

    • 您没有回答发帖者的黄金问题 - 如何使用 JSON 发布具有多张图片的产品资源。或者我必须使用多部分解析器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多