LoginSignup
0
0

More than 1 year has passed since last update.

Django Rest FrameWork で配列やファイルを含むupdate処理について

Posted at

はじめに

DRFで配列やファイル含むデータを送信する際に、multipart/form-dataで送信したが、PostManでもうまくいかず、FrontEnd側やPostManの使い方と思いこんでしまいはまってしまいました。私がやったやり方は以下のとおりです。

  • multipart/form-dataで送信 ※前提条件のとおりですが、Base64とか他にもやり方はあるそうです
  • ファイルはFileFieldを使わない
  • ViewSetで、createとupdateをオーバライドする ※Serializerでオーバライドする方法もあるそうですが、よく分かりませんでした。

目次

  1. 正解
  2. 補足
  3. 参考文献

正解

models.py
from django.db import models
from eqs.models import Eqs, EqTypes
class Infos(models.Model):
    titles = models.CharField(max_length=32)
    sammary = models.TextField(max_length=100)
    text = models.TextField()
    def __str__(self):
        return self.titles

class Files(models.Model):
     """
     ファイル格納用
     """
    Infos = models.ForeignKey('Infos', on_delete=models.CASCADE, related_name="files")
    filePath = models.CharField(primary_key=True, max_length=512)
    def __str__(self):
        return self.filePath
serializer.py
from rest_framework import serializers
from .models import Infos, Files

class InfosSerializer(serializers.ModelSerializer):
    files = serializers.StringRelatedField(many=True, read_only=True)
    class Meta:
        model = Infos
        fields = "__all__"
serializer.py
import os
from rest_framework import viewsets
from rest_framework import status
from rest_framework.generics import get_object_or_404
from rest_framework.response import Response
from .models import Infos, Files
from .serializer import InfosSerializer

UPLOAD_DIR = 'media/' # mediaフォルダに格納するためのアップロードパス

class InfosViewSet(viewsets.ModelViewSet):
     queryset = Infos.objects.all()
     serializer_class = InfosSerializer

     def create(self, request, *args, **kwargs):
          info = Infos.objects.create()
          return self.serialize(request, info)

     def update(self, request, pk, *args, **kwargs):
          info = get_object_or_404(Infos, pk=pk)
          return self.serialize(request, info)

     def serialize(self, request, bugInfo):
          serializers = InfosSerializer(instance=Info, data=request.data, partial=True)
          serializers.is_valid(raise_exception=True)
          serializers.save()
          self.delFiles(request)
          self.setFiles(info, request)

          return Response(serializers.data, status.HTTP_200_OK)

     def setFiles(self, info, request):
          files = request.FILES.getlist('addFiles[]')

          for file in files:
               # ファイル保存処理
               path = os.path.join(UPLOAD_DIR, file.name)
               destination = open(path, 'wb')
               for chunck in file.chunks():
                    destination.write(chunck)
               destination.close

               # model保存処理
               if not os.path.exists(path):
                    continue
               else:
                    fileobj = Files.objects.create(filePath=path, infos=info)
                    fileobj.save()

     def delFiles(self, request):
          str_delFiles = request.POST.getlist('delFiles[]')

          for str_delFile in str_delFiles:
               fileobj = Files.objects.get(filePath=str_delFile)
               fileobj.delete()
               os.remove(str_delFile)

補足

PostManでの確認方法

PostManでの配列の送信方法はkeyの後ろに「[]」を付ければOK(Advanced Rest Clientでも同じ)
postman.PNG

axiosでの送信方法

save.js
// 一部抜粋
    save() {
      const editedId = this.editID;
      const formData = new FormData();

      Object.entries(this.editedItem).forEach(([key, value]) => {
        if (Array.isArray(value)) {
          value.forEach((v, i) => {
            formData.append(key + '[]', v);
          });
        } else {
          formData.append(key, value);
        }
      });
      try {
        if (editedId === -1) {
          axios.post('/Info/', formData, config).then(postRes => {
            this.editedItem.id = postRes.data;
            axios.get('/Info/' + postRes.data.id + '/').then(getRes => {
              this.infos.push(getRes.data);
            });
          });
          this.close();
        } else {
          axios
            .put('/Info/' + this.editedItem.id + '/', formData, config)
            .then(putRes => {
              axios.get('/Info/' + putRes.data.id + '/').then(getRes => {
                Object.assign(this.infos[editedId], getRes.data);
              });
            });
          this.close();
        }
      } catch (error) {
        alert('DBに保存されませんでした\n' + error);
      }
    },

参考文献

0
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
0
0