1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[メモ] Django RESTful API の POST で画像データを Upload する

Last updated at Posted at 2021-08-22
本シリーズのトップページ
https://qiita.com/robozushi10/items/4559a281d0319eb62c6c

はじめに

CI による自動テストの中で、テスト結果の証拠としてキャプチャした画像(PNG)を
REST POST を使って WEBアプリに画像を Upload する機構を作成したときの抜粋である.

ファイル構成

ここでは、次のようなファイル構成で記述している.

home
|-- foo
    |-- mysite ................... Django プロジェクト
        |-- myapp ................ Django アプリ
        |   |-- models.py
        |   略
        |-- apiv1 ................ DRF
        |   |-- serializers.py
        |   |-- views.py
        |   |-- urls.py
        略
        |-- config
            |-- settings.py
            |-- urls.py
            |-- wsgi.py
            略

myapp/models.py

次の点に留意して、モデル「XXXX」を実装する.

  • imgfile = models.ImageField(upload_to=メソッド) を定義する. (下記💥)

  • 上記 upload_to で指定されたメソッドを XXXX クラス内で実装する (下記🛑)

  • フィールド「imgfile」(下記💥) に設定された値が、
    get_upload_path関数(下記🛑) の引数 filename に設定されている.

  • get_upload_path関数内(下記🛑)で「XXXX」クラスの
    「restkey」「scenario」「testcase」を組み合わせて Upload 先のパスを組み立てている.

class XXXX(models.Model):
  """ テスト結果保持 TBL """
  def 🛑get_upload_path(self, filename):
    k = self.restkey
    s = self.scenario if self.scenario else 'scenario'
    t = self.testcase if self.testcase else 'testcase'
    return '/'.join(['./images', k, s, t, filename])
  restkey   = models.CharField(verbose_name='RESTful APIキー', max_length=64)
  scenario  = models.CharField(verbose_name='シナリオ名', null=True, blank=True, max_length=40)
  testcase  = models.CharField(verbose_name='テストケース名', null=True, blank=True, max_length=64)
💥imgfile   = models.ImageField(upload_to=🛑get_upload_path, null=True, blank=True)

apiv1/serializers.py

上記モデル「XXXX」に対する DRF シリアライザである.

「XXXX」クラスの「imgfile」のみ、別途serializers.ImageField()を使って定義する.(下記💚)

from rest_framework import serializers
from XXXX.models import *

class XXXXSerializer(serializers.ModelSerializer):
  """ テスト結果保持 TBL """
 imgfile = serializers.ImageField(use_url=True)  💚
  class Meta:
    model  = XXXX
    fields = '__all__'  

参考にした記事

内容 URL
REST によるファイルのアップロード方法 https://stackoverflow.com/questions/45559471/django-rest-framework-upload-image-api

 

config/urls.py

ルーティングを定義する.

エンドポイントとして「api/v1/」が指定された場合は、
後述のapi/v1/urls.py でルーティングさせる.

from django.contrib import admin
from django.urls import path
from django.urls import include
from django.conf.urls import url, include
from django.views.generic import TemplateView
from django.views.generic import RedirectView
from apiv2 import views

urlpatterns = [
  path('api/v1/', include('apiv1.urls')),
]

apiv1/urls.py

DRF に関するルーティングを定義する.
下記🏷️と📛の詳細については後述している.

from django.urls import path, include
from rest_framework import routers
from . import views
 
urlpatterns = [
  path('', include(router.urls)),
  path('myapp/XXXX/',      🏷️views.XXXXListCreateAPIView.as_view()),
  path('myapp/XXXX/<pk>/', 📛views.XXXXRetrieveUpdateDestroyAPIView.as_view()),
]

apiv1/views.py

前述の 🏷️ と 📛 のクラスの実装である.
次の 🏷️ と 📛 のクラスに対して、それぞれ次の 1行以外を追加した以外は特殊な記述は無い (はず)

parser_classes = (MultiPartParser, FormParser) #! 🎰引用

from rest_framework import generics
from rest_framework import status
from rest_framework import views  #! 📘引用
from django.shortcuts import get_object_or_404  #! 📘引用
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response

from rest_framework.parsers import MultiPartParser, FormParser #! 🎰引用
from rest_framework.generics import ListAPIView 

from myapp.models import *
from .serializers import *
 
class XXXXListCreateAPIView(views.APIView):🏷️
  """ XXXX の取得(一覧)・登録 API クラス """
  parser_classes = (MultiPartParser, FormParser) #! 🎰引用

  def get(self, request, *args, **kwargs):
    l = XXXX.objects.all()
    ser = XXXXSerializer(instance=l, many=True)
    return Response(ser.data, status.HTTP_200_OK)

  def post(self, request, *args, **kwargs):
    ser = XXXXSerializer(data=request.data)
    ser.is_valid(raise_exception=True)
    ser.save()
    return Response(ser.data, status.HTTP_201_CREATED)


class XXXXRetrieveUpdateDestroyAPIView(views.APIView):
  """ XXXX の取得(詳細)・更新・一部更新・削除 API クラス """
  parser_classes = (MultiPartParser, FormParser) #! 🎰引用

  def get(self, request, pk, *args, **kwargs):
    oc = get_object_or_404(XXXX, pk=pk)
    ser = XXXXSerializer(instance=oc)
    return Response(ser.data, status.HTTP_200_OK)

  def put(self, request, pk, *args, **kwargs):
    oc = get_object_or_404(XXXX, pk=pk)
    ser = XXXXSerializer(instance=oc, data=request.data)
    ser.is_valid(raise_exception=True)
    ser.save()
    return Response(ser.data, status.HTTP_200_OK)
    
  def patch(self, request, pk, *args, **kwargs):
    oc = get_object_or_404(XXXX, pk=pk)
    ser = XXXXSerializer(instance=oc, data=request.data, partial=True)
    ser.is_valid(raise_exception=True)
    ser.save()
    return Response(ser.data, status.HTTP_200_OK)

  def delete(self, request, pk, *args, **kwargs):
    oc = get_object_or_404(XXXX, pk=pk)
    ser.delete()
    return Response(status.HTTP_204_NO_CONTENT)

参考にした記事

内容 URL 備考
APIView のために必要 現場で使える Django REST Framework の教科書 (Django の教科書シリーズ) 上記📘
REST によるファイルのアップロード方法 https://stackoverflow.com/questions/45559471/django-rest-framework-upload-image-api 上記🎰

 

以上.

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?