如何设置允许上传 JSON 数据和图像的 API?

How to setup an API which allows uploading JSON data and an image?

我用 Django REST Framework 构建了一个 API。以下视图集为客户端传输的 JSON 对象创建了一个数据库条目。

class ArticleViewSet(mixins.CreateModelMixin,
                    mixins.RetrieveModelMixin,
                    mixins.ListModelMixin,
                    viewsets.GenericViewSet):
    """
    API endpoint that allows articles to be created or viewed.
    """
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

现在,我想连同 JSON 数据一起发送 图像 。我想客户端必须将其请求作为 "multipart/form-data" mime 类型发送。如有不妥请指正
因此,我添加了一个 MultiPartParser:

parser_classes = (MultiPartParser,)

为了在服务器端使用 ipdb 调试请求,我添加了 create 方法:

class ArticleViewSet(mixins.CreateModelMixin,
                    mixins.RetrieveModelMixin,
                    mixins.ListModelMixin,
                    viewsets.GenericViewSet):
    """
    API endpoint that allows articles to be created or viewed.
    """
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    parser_classes = (MultiPartParser,)

    def create(request, *args, **kwargs):
        ipdb.set_trace()
        return Response(request)

如何实际检查request是否收到数据?

经验教训

  1. 没有必要配置 MultiPartParser 因为它是 loaded by default
  2. 我添加的create方法的签名是错误的。它必须是 create(self, request, *args, **kwargs)。有了它,您将能够检查 request 对象和 request.data。感谢 IRC 的 JockeTF #restframework !!
  3. 可以使用 cURL 从命令行发送测试请求,如下所示:

    $ curl -vX POST http://localhost:8000/articles/ \
    -H "Content-Type: multipart/form-data" \
    -H "Accept:application/json" \
    -F "title=Test" \
    -F "author_name=cURL" \
    -F "article_photo=@/home/user/Desktop/article-photo.png"
    

是的,您的客户应该这样做(js 示例)

var formdata = new FormData();
formdata.append("image", file);

在 Django 中,上传的文件可以在 request.FILES['image']

中访问

为此检查 Django 文档 https://docs.djangoproject.com/en/1.7/topics/http/file-uploads/

这是我所做的...

  1. 安装 Pillow package 进行图像处理
  2. 使用新属性扩展您的模型

    article_photo = models.ImageField(blank=True)
    
  3. settings.py中配置以下设置:

    • 对于开发环境:

      ENV_PATH = os.path.abspath(os.path.dirname(__file__))
      
      """
      Absolute filesystem path to the directory that 
      will hold user-uploaded files.
      """
      MEDIA_ROOT = os.path.join(ENV_PATH, 'media/')
      
      """
      Relative browser URL you should access your media files from
      """
      MEDIA_URL = '/media/'
      
    • 对于生产环境:

      """
      Absolute filesystem path to the directory that 
      will hold user-uploaded files.
      """
      MEDIA_ROOT = '/myapp/api/media'
      
      """
      Relative browser URL you should access your media files from
      Path must be served from webserver (Nginx, Apache, ..) configuration
      """
      MEDIA_URL = '/myapp/media/'
      
  4. 创建新迁移并运行它。

    $ python manage.py makemigrations  
    $ python manage.py migrate
    
  5. 使用cURL从命令行发送测试请求如下:

    $ curl -vX POST http://localhost:8000/articles/ \
    -H "Content-Type: multipart/form-data" \
    -H "Accept:application/json" \
    -F "title=Test" \
    -F "author_name=cURL" \
    -F "article_photo=@/home/user/Desktop/article-photo.png"