Django REST框架+ Django REST Swagger + ImageField

时间:2022-06-24 03:33:24

I created a simple Model with an ImageField and I wanna make an api view with django-rest-framework + django-rest-swagger, that is documented and is able to upload the file.

我用ImageField创建了一个简单的模型,我想用django-res -framework + django-res -swagger创建一个api视图,它有文档记录,可以上传文件。

Here is what I got:

以下是我得到的:

models.py

models.py

from django.utils import timezone
from django.db import models

class MyModel(models.Model):

    source = models.ImageField(upload_to=u'/photos')
    is_active = models.BooleanField(default=False)
    created_at = models.DateTimeField(default=timezone.now)

    def __unicode__(self):
        return u"photo {0}".format(self.source.url)

serializer.py

serializer.py

from .models import MyModel

class MyModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = MyModel
        fields = [
            'id',
            'source',
            'created_at',
        ]

views.py

views.py

from rest_framework import generics
from .serializer import MyModelSerializer

class MyModelView(generics.CreateAPIView):
    serializer_class = MyModelSerializer
    parser_classes = (FileUploadParser, )

    def post(self, *args, **kwargs):
        """
            Create a MyModel
            ---
            parameters:
                - name: source
                  description: file
                  required: True
                  type: file
            responseMessages:
                - code: 201
                  message: Created
        """
        return super(MyModelView, self).post(self, *args, **kwargs)

urls.py

urls . py

from weddings.api.views import MyModelView

urlpatterns = patterns(
    '',
    url(r'^/api/mymodel/$', MyModelView.as_view()),
)

For me this should be pretty simple. However, I can't make the upload work. I always get this error response: Django REST框架+ Django REST Swagger + ImageField

对我来说,这应该很简单。但是,我不能让上传工作。我总是会得到这样的错误响应:

I've read this part of the documentation from django-rest-framework:

我已经阅读了django-res -framework的这部分文档:

If the view used with FileUploadParser is called with a filename URL keyword argument, then that argument will be used as the filename. If it is called without a filename URL keyword argument, then the client must set the filename in the Content-Disposition HTTP header. For example Content-Disposition: attachment; filename=upload.jpg.

如果FileUploadParser使用的视图使用文件名URL关键字参数调用,那么该参数将用作文件名。如果没有文件名URL关键字参数就调用它,那么客户端必须在内容配置HTTP头中设置文件名。例如附加项:附件;文件名= upload.jpg。

However the Header is being passed by django-rest-swagger in the Request Payload property (from chrome console).

然而,在请求有效负载属性(来自chrome控制台)中,消息头被django- reswagger传递。

If any more info is necessary, please let me know.

如果需要更多的信息,请告诉我。

I'm using Django==1.8.8, djangorestframework==3.3.2 and django-rest-swagger==0.3.4.

我用Django= 1.8.8, djangorestframework= 3.3.2, Django -res -swagger= 0.3.4。

3 个解决方案

#1


7  

I got this working by making a couple of changes to your code.

我对您的代码做了几处修改,使它能够正常工作。

First, in models.py, change ImageField name to file and use relative path to upload folder. When you upload file as binary stream, it's available in request.data dictionary under file key (request.data.get('file')), so the cleanest option is to map it to the model field with the same name.

首先,在模型。py,将ImageField名称改为file,并使用相对路径上传文件夹。当您上传文件作为二进制流,它是可请求的。文件键(request.data.get('file'))下的数据字典,因此最干净的选项是将它映射到具有相同名称的模型字段。

from django.utils import timezone
from django.db import models


class MyModel(models.Model):

    file = models.ImageField(upload_to=u'photos')
    is_active = models.BooleanField(default=False)
    created_at = models.DateTimeField(default=timezone.now)

    def __unicode__(self):
        return u"photo {0}".format(self.file.url)

In serializer.py, rename source field to file:

在序列化器。py,将源字段重命名为file:

class MyModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = MyModel
        fields = ('id', 'file', 'created_at')

In views.py, don't call super, but call create():

在视图。py,不调用super,调用create():

from rest_framework import generics
from rest_framework.parsers import FileUploadParser

from .serializer import MyModelSerializer


class MyModelView(generics.CreateAPIView):
    serializer_class = MyModelSerializer
    parser_classes = (FileUploadParser,)

    def post(self, request, *args, **kwargs):
        """
            Create a MyModel
            ---
            parameters:
                - name: file
                  description: file
                  required: True
                  type: file
            responseMessages:
                - code: 201
                  message: Created
        """
        return self.create(request, *args, **kwargs)

I've used Postman Chrome extension to test this. I've uploaded images as binaries and I've manually set two headers:

我用Postman Chrome扩展来测试这个。我已经上传图片作为二进制文件,我手动设置了两个标题:

Content-Disposition: attachment; filename=upload.jpg
Content-Type: */*

#2


3  

It has been my experience that the FileUploadParser works with this format of a request:

根据我的经验,FileUploadParser可以处理这种请求格式:

    curl -X POST -H "Content-Type:multipart/form-data" \
                 -F "file=@{filename};type=image/jpg" \
                 https://endpoint.com/upload-uri/

The request.data['file'] in your view will have the file.

请求。在你的视图中的数据['file']将有文件。

Maybe if you try a Content-Type:multipart/form-data header, you will have luck.

如果您尝试使用内容类型:multipart/form-data header,那么您将会很幸运。

#3


3  

This is the final solution I came up with:

这是我想到的最终解决方案:

from rest_framework import generics
from rest_framework.parsers import FormParser, MultiPartParser
from .serializer import MyModelSerializer

class MyModelView(generics.CreateAPIView):
    serializer_class = MyModelSerializer
    parser_classes = (FormParser, MultiPartParser)

    def post(self, *args, **kwargs):
        """
            Create a MyModel
            ---
            parameters:
                - name: source
                  description: file
                  required: True
                  type: file
            responseMessages:
                - code: 201
                  message: Created
        """
        return super(MyModelView, self).post(self, *args, **kwargs)

All I had to do was change the parsers from FileUploadParser to (FormParser, MultiPartParser)

我所要做的就是将解析器从FileUploadParser更改为(FormParser, MultiPartParser)

#1


7  

I got this working by making a couple of changes to your code.

我对您的代码做了几处修改,使它能够正常工作。

First, in models.py, change ImageField name to file and use relative path to upload folder. When you upload file as binary stream, it's available in request.data dictionary under file key (request.data.get('file')), so the cleanest option is to map it to the model field with the same name.

首先,在模型。py,将ImageField名称改为file,并使用相对路径上传文件夹。当您上传文件作为二进制流,它是可请求的。文件键(request.data.get('file'))下的数据字典,因此最干净的选项是将它映射到具有相同名称的模型字段。

from django.utils import timezone
from django.db import models


class MyModel(models.Model):

    file = models.ImageField(upload_to=u'photos')
    is_active = models.BooleanField(default=False)
    created_at = models.DateTimeField(default=timezone.now)

    def __unicode__(self):
        return u"photo {0}".format(self.file.url)

In serializer.py, rename source field to file:

在序列化器。py,将源字段重命名为file:

class MyModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = MyModel
        fields = ('id', 'file', 'created_at')

In views.py, don't call super, but call create():

在视图。py,不调用super,调用create():

from rest_framework import generics
from rest_framework.parsers import FileUploadParser

from .serializer import MyModelSerializer


class MyModelView(generics.CreateAPIView):
    serializer_class = MyModelSerializer
    parser_classes = (FileUploadParser,)

    def post(self, request, *args, **kwargs):
        """
            Create a MyModel
            ---
            parameters:
                - name: file
                  description: file
                  required: True
                  type: file
            responseMessages:
                - code: 201
                  message: Created
        """
        return self.create(request, *args, **kwargs)

I've used Postman Chrome extension to test this. I've uploaded images as binaries and I've manually set two headers:

我用Postman Chrome扩展来测试这个。我已经上传图片作为二进制文件,我手动设置了两个标题:

Content-Disposition: attachment; filename=upload.jpg
Content-Type: */*

#2


3  

It has been my experience that the FileUploadParser works with this format of a request:

根据我的经验,FileUploadParser可以处理这种请求格式:

    curl -X POST -H "Content-Type:multipart/form-data" \
                 -F "file=@{filename};type=image/jpg" \
                 https://endpoint.com/upload-uri/

The request.data['file'] in your view will have the file.

请求。在你的视图中的数据['file']将有文件。

Maybe if you try a Content-Type:multipart/form-data header, you will have luck.

如果您尝试使用内容类型:multipart/form-data header,那么您将会很幸运。

#3


3  

This is the final solution I came up with:

这是我想到的最终解决方案:

from rest_framework import generics
from rest_framework.parsers import FormParser, MultiPartParser
from .serializer import MyModelSerializer

class MyModelView(generics.CreateAPIView):
    serializer_class = MyModelSerializer
    parser_classes = (FormParser, MultiPartParser)

    def post(self, *args, **kwargs):
        """
            Create a MyModel
            ---
            parameters:
                - name: source
                  description: file
                  required: True
                  type: file
            responseMessages:
                - code: 201
                  message: Created
        """
        return super(MyModelView, self).post(self, *args, **kwargs)

All I had to do was change the parsers from FileUploadParser to (FormParser, MultiPartParser)

我所要做的就是将解析器从FileUploadParser更改为(FormParser, MultiPartParser)