codememo

Django Rest Framework 파일 업로드

tipmemo 2023. 3. 19. 18:15
반응형

Django Rest Framework 파일 업로드

저는 Django Rest Framework와 AngularJs를 사용하여 파일을 업로드하고 있습니다.내 뷰 파일은 다음과 같습니다.

class ProductList(APIView):
    authentication_classes = (authentication.TokenAuthentication,)
    def get(self,request):
        if request.user.is_authenticated(): 
            userCompanyId = request.user.get_profile().companyId
            products = Product.objects.filter(company = userCompanyId)
            serializer = ProductSerializer(products,many=True)
            return Response(serializer.data)

    def post(self,request):
        serializer = ProductSerializer(data=request.DATA, files=request.FILES)
        if serializer.is_valid():
            serializer.save()
            return Response(data=request.DATA)

마지막 포스트 방법은 모든 데이터를 반환하기 때문에 몇 가지 질문이 있습니다.

  • 무엇이 request.FILES
  • 파일 필드를 직렬화하는 방법
  • 파서를 어떻게 사용하면 좋을까요?

편집자 메모:

  • 에서는 ""를 사용합니다.pre_save장고 REST 3.0입니다.
  • 에서는 Django REST는MultiPartParser는 기본적으로 사용할 수 있어야 합니다.이것에 의해, 특별한 처리 없이 파일을 업 로드할 수 있습니다.예에 대해서는, 다음의 회답을 참조해 주세요.

같은 스택을 사용하고 있으며 파일 업로드의 예도 찾고 있습니다만, Model View를 사용하고 있기 때문에, 보다 심플하게 할 수 있습니다.APIView 대신 설정.키는 pre_save 훅으로 판명되었습니다.angular-file-upload 모듈과 함께 사용하게 되었습니다.

# Django
class ExperimentViewSet(ModelViewSet):
    queryset = Experiment.objects.all()
    serializer_class = ExperimentSerializer

    def pre_save(self, obj):
        obj.samplesheet = self.request.FILES.get('file')

class Experiment(Model):
    notes = TextField(blank=True)
    samplesheet = FileField(blank=True, default='')
    user = ForeignKey(User, related_name='experiments')

class ExperimentSerializer(ModelSerializer):
    class Meta:
        model = Experiment
        fields = ('id', 'notes', 'samplesheet', 'user')
// AngularJS
controller('UploadExperimentCtrl', function($scope, $upload) {
    $scope.submit = function(files, exp) {
        $upload.upload({
            url: '/api/experiments/' + exp.id + '/',
            method: 'PUT',
            data: {user: exp.user.id},
            file: files[0]
        });
    };
});

FileUploadParser를 사용하면 모든 것이 요청에 포함됩니다.대신 put 방식을 사용하세요.예는 문서에 나와 있습니다.

class FileUploadView(views.APIView):
    parser_classes = (FileUploadParser,)

    def put(self, request, filename, format=None):
        file_obj = request.FILES['file']
        # do some stuff with uploaded file
        return Response(status=204)

드디어 장고를 사용하여 이미지를 업로드 할 수 있게 되었습니다.여기 작업 코드가 있습니다.

views.py

class FileUploadView(APIView):
    parser_classes = (FileUploadParser, )

    def post(self, request, format='jpg'):
        up_file = request.FILES['file']
        destination = open('/Users/Username/' + up_file.name, 'wb+')
        for chunk in up_file.chunks():
            destination.write(chunk)
        destination.close()  # File should be closed only after all chuns are added

        # ...
        # do some stuff with uploaded file
        # ...
        return Response(up_file.name, status.HTTP_201_CREATED)

urls.py

urlpatterns = patterns('', 
url(r'^imageUpload', views.FileUploadView.as_view())

업로드할 컬 요청

curl -X POST -S -H -u "admin:password" -F "file=@img.jpg;type=image/jpg" 127.0.0.1:8000/resourceurl/imageUpload

내 경험상 파일 필드에 대해 특별히 할 필요가 없으며 파일 필드를 활용하도록 지시하기만 하면 됩니다.

from rest_framework import routers, serializers, viewsets

class Photo(django.db.models.Model):
    file = django.db.models.ImageField()

    def __str__(self):
        return self.file.name

class PhotoSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Photo
        fields = ('id', 'file')   # <-- HERE

class PhotoViewSet(viewsets.ModelViewSet):
    queryset = models.Photo.objects.all()
    serializer_class = PhotoSerializer

router = routers.DefaultRouter()
router.register(r'photos', PhotoViewSet)

api_urlpatterns = ([
    url('', include(router.urls)),
], 'api')
urlpatterns += [
    url(r'^api/', include(api_urlpatterns)),
]

파일을 업로드할 준비가 되었습니다.

curl -sS http://example.com/api/photos/ -F 'file=@/path/to/file'

-F field=value델델있있있있있있대대대대대대대대대대 。★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

하루 종일 고민하다가 알게 된 건...

파일을 업로드하여 데이터를 전송해야 하는 사용자에게 파일을 바로 사용할 수 있는 방법은 없습니다.이에 대한 JSON API 사양에는 미해결 문제가 있습니다.제가 본 한 가지 가능성은multipart/relatedDRF에서는 구현이 매우 어렵다고 생각합니다.

가 요청한 이었습니다.FormData각 파일을 파일로 전송하고 다른 모든 데이터를 텍스트로 전송합니다.데이터를 텍스트로 전송하려면 두 가지 선택사항이 있습니다.케이스 1) 각 데이터를 키-값 쌍으로 전송하거나 케이스 2) 데이터라는 단일 키를 사용하여 전체 JSON을 값의 문자열로 전송할 수 있습니다.

첫 번째 방법은 단순 필드가 있는 경우 즉시 사용할 수 있지만 중첩된 직렬화가 있는 경우 문제가 됩니다.멀티파트 파서는 중첩된 필드를 구문 분석할 수 없습니다.

이하에, 양쪽의 케이스의 실장을 나타냅니다.

models.py

class Posts(models.Model):
    id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False)
    caption = models.TextField(max_length=1000)
    media = models.ImageField(blank=True, default="", upload_to="posts/")
    tags = models.ManyToManyField('Tags', related_name='posts')

serializers.py -> 특별한 변경은 필요 없습니다.쓰기 가능한 Many To Many Field 구현으로 인해 시리얼라이저가 너무 길기 때문에 여기에 표시되지 않습니다.

views.py

class PostsViewset(viewsets.ModelViewSet):
    serializer_class = PostsSerializer
    #parser_classes = (MultipartJsonParser, parsers.JSONParser) use this if you have simple key value pair as data with no nested serializers
    #parser_classes = (parsers.MultipartParser, parsers.JSONParser) use this if you want to parse json in the key value pair data sent
    queryset = Posts.objects.all()
    lookup_field = 'id'

첫 번째 방법을 따르고 Json 이외의 데이터를 키와 값의 쌍으로만 전송하는 경우에는 커스텀파서 클래스가 필요 없습니다.DRF'd MultipartParser가 작업을 수행합니다.그러나 두 번째 경우 또는 네스트된 시리얼라이저가 있는 경우(표시한 바와 같이) 다음과 같은 커스텀파서가 필요합니다.

utils.py

from django.http import QueryDict
import json
from rest_framework import parsers

class MultipartJsonParser(parsers.MultiPartParser):

    def parse(self, stream, media_type=None, parser_context=None):
        result = super().parse(
            stream,
            media_type=media_type,
            parser_context=parser_context
        )
        data = {}

        # for case1 with nested serializers
        # parse each field with json
        for key, value in result.data.items():
            if type(value) != str:
                data[key] = value
                continue
            if '{' in value or "[" in value:
                try:
                    data[key] = json.loads(value)
                except ValueError:
                    data[key] = value
            else:
                data[key] = value

        # for case 2
        # find the data field and parse it
        data = json.loads(result.data["data"])

        qdict = QueryDict('', mutable=True)
        qdict.update(data)
        return parsers.DataAndFiles(qdict, result.files)

이 시리얼라이저는 기본적으로 값의 모든 JSON 콘텐츠를 해석합니다.

두 경우 모두 우체부의 요청 예를 다음에 나타냅니다.

케이스 1

케이스 2

Django Rest Framework용 Model Viewset의 가장 쉬운 예에 관심이 있는 사용자.

모델은 다음과 같습니다.

class MyModel(models.Model):
    name = models.CharField(db_column='name', max_length=200, blank=False, null=False, unique=True)
    imageUrl = models.FileField(db_column='image_url', blank=True, null=True, upload_to='images/')

    class Meta:
        managed = True
        db_table = 'MyModel'

시리얼라이저,

class MyModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = MyModel
        fields = "__all__"

그리고 뷰는

class MyModelView(viewsets.ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer

우체국에서의 테스트,

여기에 이미지 설명 입력

models.py

from django.db import models

import uuid

class File(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    file = models.FileField(blank=False, null=False)
    
    def __str__(self):
        return self.file.name

serializers.py

from rest_framework import serializers
from .models import File

class FileSerializer(serializers.ModelSerializer):
    class Meta:
        model = File
        fields = "__all__"

views.py

from django.shortcuts import render
from rest_framework.parsers import FileUploadParser
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status

from .serializers import FileSerializer


class FileUploadView(APIView):
    permission_classes = []
    parser_class = (FileUploadParser,)

    def post(self, request, *args, **kwargs):

      file_serializer = FileSerializer(data=request.data)

      if file_serializer.is_valid():
          file_serializer.save()
          return Response(file_serializer.data, status=status.HTTP_201_CREATED)
      else:
          return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

urls.py

from apps.files import views as FileViews

urlpatterns = [
    path('api/files', FileViews.FileUploadView.as_view()),
]

설정을 지정합니다.화이

# file uload parameters
MEDIA_URL =  '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

을 고고고 send send send send send로 송신하다api/files하여 ""에 하여''form-data 들 fieldfile이 업로드 /mediaDB ID입니다.

이 문제를 Model View로 해결했습니다.및 ModelSerializer를 설정합니다.이것이 지역사회에 도움이 되기를 바랍니다.

또, 검증과 오브젝트-> JSON(및 그 반대) 로그인을 뷰가 아닌 시리얼라이저로 하는 것도 추천합니다.

그것을 예로 들어 이해합시다.

예를 들어 FileUploader API를 만들고 싶습니다.ID, file_path, file_name, 크기, 소유자 등의 필드를 데이터베이스에 저장합니다.아래 샘플 모델을 참조하십시오.

class FileUploader(models.Model):
    file = models.FileField()
    name = models.CharField(max_length=100) #name is filename without extension
    version = models.IntegerField(default=0)
    upload_date = models.DateTimeField(auto_now=True, db_index=True)
    owner = models.ForeignKey('auth.User', related_name='uploaded_files')
    size = models.IntegerField(default=0)

API는 다음과 같습니다.

  1. 취득:

GET 엔드포인트를 실행할 때 업로드된 모든 파일에 대해 위의 모든 필드가 필요합니다.

  1. 투고:

그러나 사용자가 파일을 작성/업로드하려면 이러한 모든 필드를 넘겨야 하는 이유를 알아야 합니다.파일을 업로드하면 시리얼라이저는 업로드된 FILE에서 나머지 필드를 가져올 수 있습니다.

서라이저:질문:목적에 맞게 아래 시리얼라이저를 만들었습니다.하지만 이것이 그것을 구현하는 올바른 방법인지 확실하지 않다.

class FileUploaderSerializer(serializers.ModelSerializer):
    # overwrite = serializers.BooleanField()
    class Meta:
        model = FileUploader
        fields = ('file','name','version','upload_date', 'size')
        read_only_fields = ('name','version','owner','upload_date', 'size')

   def validate(self, validated_data):
        validated_data['owner'] = self.context['request'].user
        validated_data['name'] = os.path.splitext(validated_data['file'].name)[0]
        validated_data['size'] = validated_data['file'].size
        #other validation logic
        return validated_data

    def create(self, validated_data):
        return FileUploader.objects.create(**validated_data)

참조용 뷰 세트:

class FileUploaderViewSet(viewsets.ModelViewSet):
    serializer_class = FileUploaderSerializer
    parser_classes = (MultiPartParser, FormParser,)

    # overriding default query set
    queryset = LayerFile.objects.all()

    def get_queryset(self, *args, **kwargs):
        qs = super(FileUploaderViewSet, self).get_queryset(*args, **kwargs)
        qs = qs.filter(owner=self.request.user)
        return qs

더 깨끗하고 유지보수가 쉽다고 느끼는 다른 옵션을 쓰고 싶습니다.defaultRouter를 사용하여 뷰셋의 CRUD URL을 추가하고 동일한 뷰셋 내에서 업로더 뷰를 지정하는 고정 URL을 하나 더 추가합니다.

**** views.py 

from rest_framework import viewsets, serializers
from rest_framework.decorators import action, parser_classes
from rest_framework.parsers import JSONParser, MultiPartParser
from rest_framework.response import Response
from rest_framework_csv.parsers import CSVParser
from posts.models import Post
from posts.serializers import PostSerializer     


class PostsViewSet(viewsets.ModelViewSet):

    queryset = Post.objects.all()
    serializer_class = PostSerializer 
    parser_classes = (JSONParser, MultiPartParser, CSVParser)


    @action(detail=False, methods=['put'], name='Uploader View', parser_classes=[CSVParser],)
    def uploader(self, request, filename, format=None):
        # Parsed data will be returned within the request object by accessing 'data' attr  
        _data = request.data

        return Response(status=204)

프로젝트의 주요 URL.화이

**** urls.py 

from rest_framework import routers
from posts.views import PostsViewSet


router = routers.DefaultRouter()
router.register(r'posts', PostsViewSet)

urlpatterns = [
    url(r'^posts/uploader/(?P<filename>[^/]+)$', PostsViewSet.as_view({'put': 'uploader'}), name='posts_uploader')
    url(r'^', include(router.urls), name='root-api'),
    url('admin/', admin.site.urls),
]

.-README

@action decorator를 클래스 메서드 'uploader'에 추가하면 마법이 발생합니다."put=['put'" 인수를 지정함으로써 PUT 요청만 허용하므로 파일 업로드에 적합합니다.

또한 "parser_classes" 인수를 추가하여 콘텐츠를 해석할 파서를 선택할 수 있습니다.rest_framework_csv 패키지에서 CSVParser를 추가했습니다.이 기능이 필요한 경우 특정 유형의 파일만 받을 수 있다는 것을 보여주기 위해 저는 "Content-Type: text/csv"만 받습니다.주의: 커스텀 파서를 추가할 경우 ViewSet의 parsers_classes에 지정해야 합니다.이는 업로더 메서드 파서에 액세스하기 전에 요청이 허용된 media_type과 메인(클래스) 파서를 비교하기 때문입니다.

이제 이 방법을 사용하는 방법과 URL에서 구현할 수 있는 위치를 Django에게 알려야 합니다.이 때 고정 URL을 추가합니다(간단한 목적).이 URL은 나중에 메서드에서 전달될 "filename" 인수를 사용합니다.리스트 내의 http protocol('PUT')을 지정하는 이 메서드를 PostsViewSet.as_view 메서드에 전달해야 합니다.

다음 URL에 도착하면

 http://example.com/posts/uploader/ 

"Content-Type" 및 "Content-Disposition: attachment; filename="something.csv" 헤더가 지정된 PUT 요청을 예상합니다.

curl -v -u user:pass http://example.com/posts/uploader/ --upload-file ./something.csv --header "Content-type:text/csv"

일부 솔루션은 권장되지 않습니다(Django 3.0+에는 request.data를 사용해야 합니다).그 중 일부는 입력의 유효성을 검사하지 않습니다.또, swager annotation이 있는 솔루션을 주시면 감사하겠습니다.따라서 다음 코드를 사용할 것을 권장합니다.

from drf_yasg.utils import swagger_auto_schema
from rest_framework import serializers
from rest_framework.parsers import MultiPartParser
from rest_framework.response import Response
from rest_framework.views import APIView


class FileUploadAPI(APIView):
    parser_classes = (MultiPartParser, )

    class InputSerializer(serializers.Serializer):
        image = serializers.ImageField()

    @swagger_auto_schema(
        request_body=InputSerializer
    )
    def put(self, request):
        input_serializer = self.InputSerializer(data=request.data)
        input_serializer.is_valid(raise_exception=True)

        # process file
        file = input_serializer.validated_data['image']

        return Response(status=204)

이 뷰를 사용하여 파일을 aws에 업로드했습니다.여기서 upload_file은 도우미 기능입니다.전체적으로 이 뷰를 사용하여 파일을 폼 데이터로 업로드 할 수 있습니다.

class FileUploadView(GenericAPIView):

    def post(self, request):
        try:
            file = request.data['file']
            if file.content_type == 'image/png' or file.content_type == 'image/jpeg':
                file_name = upload_file(file)
                return Response({"name": file_name}, status=status.HTTP_202_ACCEPTED)
            else:
                raise UnsupportedMediaType(file.content_type)
        except KeyError:
            return Response("file missing.", status=status.HTTP_404_NOT_FOUND)

단일 업로드 파일 또는 여러 파일을 단일 요청으로 처리하는 가장 간단한 방법은 다음과 같습니다.

@api_view(['POST'])
def file_list(request):  # use APIview or function based view or any view u want
    # for single file
    file = request.FILES["file"]
    print(file)
    # Do what ever you want with it

    # for multiple file
    files = request.FILES.getlist('file')
    for file in files:
        print(file)
        # Do what ever you want with it
    from rest_framework import status
    from rest_framework.response import Response
    class FileUpload(APIView):
         def put(request):
             try:
                file = request.FILES['filename']
                #now upload to s3 bucket or your media file
             except Exception as e:
                   print e
                   return Response(status, 
                           status.HTTP_500_INTERNAL_SERVER_ERROR)
             return Response(status, status.HTTP_200_OK)

모델뷰Set을 사용하고 있다면, 실제로는 이것으로 끝입니다.★★★★★★★★★★★★★★★★★★★★★★★★★★★★! ModelSerializer를 설정하기만 하면 .content-type=multipart/form-data;를 참조해 주세요.

하지만 아시다시피 json 포맷으로 파일을 보낼 수 없습니다.(클라이언트에서 content-type이 application/json으로 설정되어 있는 경우).Base64 형식을 사용하지 않는 한.

두 가지 선택지가 있습니다.

  • 를 놓다ModelViewSet and 그리고.ModelSerializer handle the job and send the request using 작업을 처리하여 요청을 전송합니다.content-type=multipart/form-data;
  • 비 하에서 필드를 설정합니다.ModelSerializer as ~하듯이Base64ImageField (or) Base64FileField and tell your client to encode the file to 클라이언트에 파일을 부호화하도록 지시합니다.Base64 and set the 를 설정합니다.content-type=application/json
from rest_framework import status, generics
from rest_framework.response import Response
from rest_framework import serializers
import logging
logger = logging.getLogger(__name__)`enter code here`
class ImageUploadSerializer(serializers.Serializer):
    file = serializers.FileField()

class UploadImages(generics.GenericAPIView):
    
    serializer_class = ImageUploadSerializer
    permission_classes = [IsAuthenticated, ]

    def post(self, request):

        try:
            data = self.serializer_class(data=request.data)
            if data.is_valid() is False:
                return Response({'error': ERROR_MESSAGES.get('400')}, status=status.HTTP_400_BAD_REQUEST)
                is_file_upload_success, file_item = save_aws_article_image(data.validated_data.get('file'),
                                                                           request.user, upload_type)

            if is_file_upload_success:
                logger.info('{0} file uploaded {1}'.format(file_item['file_obj'].path, datetime.now()))
                return Response({'path': file_item['file_obj'].path, 'id': file_item['file_obj'].uuid,
                                 'name': file_item['file_obj'].name},
                                status=status.HTTP_201_CREATED)
        except Exception as e:
            logger.error(e, exc_info=True)
            return Response({"error": e}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

o 흥미로운 프레임워크 요청 데이터는 o 구 이 해 석 터 해 됩 의 니 in다 d-에에 request--jang is datajangframework데rest요는 pars-framework theParsers.
http://www.django-rest-framework.org/api-guide/parsers/http: www.django-rest-framework.org/api-guide/parsers/: :

"django-rest-framework" 를 합니다.JSONParser데이터를 json으로 해석하기 때문에 파일은 해석되지 않습니다.
다른 데이터와 함께 파일을 구문 분석하려면 다음 구문 분석기 클래스 중 하나를 사용해야 합니다.

FormParser
MultiPartParser
FileUploadParser
def post(self,request):
        serializer = ProductSerializer(data=request.DATA, files=request.FILES)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)

이것이 도움이 되기를 바라며 제가 적용한 접근법 중 하나입니다.

     class Model_File_update(APIView):
         parser_classes = (MultiPartParser, FormParser)
         permission_classes = [IsAuthenticated]  # it will check if the user is authenticated or not
         authentication_classes = [JSONWebTokenAuthentication]  # it will authenticate the person by JSON web token

         def put(self, request):
            id = request.GET.get('id')
            obj = Model.objects.get(id=id)
            serializer = Model_Upload_Serializer(obj, data=request.data)
            if serializer.is_valid():
               serializer.save()
               return Response(serializer.data, status=200)
            else:
               return Response(serializer.errors, status=400)

파서 클래스를 생성하여 특정 필드를 해석하고 표준 DRF 시리얼라이저에 직접 공급함으로써 @Nithin의 응답을 DRF의 기존 시리얼라이저 시스템과 직접 연계할 수 있습니다.

from django.http import QueryDict
import json
from rest_framework import parsers


def gen_MultipartJsonParser(json_fields):
    class MultipartJsonParser(parsers.MultiPartParser):

        def parse(self, stream, media_type=None, parser_context=None):
            result = super().parse(
                stream,
                media_type=media_type,
                parser_context=parser_context
            )
            data = {}
            # find the data field and parse it
            qdict = QueryDict('', mutable=True)
            for json_field in json_fields:
                json_data = result.data.get(json_field, None)
                if not json_data:
                    continue
                data = json.loads(json_data)
                if type(data) == list:
                    for d in data:
                        qdict.update({json_field: d})
                else:
                    qdict.update({json_field: data})

            return parsers.DataAndFiles(qdict, result.files)

    return MultipartJsonParser

이것은 다음과 같이 사용됩니다.

class MyFileViewSet(ModelViewSet):
    parser_classes = [gen_MultipartJsonParser(['tags', 'permissions'])]
    #                                           ^^^^^^^^^^^^^^^^^^^
    #                              Fields that need to be further JSON parsed
    ....

DRF 뷰셋파일은 react(axios)를 사용하여 audioBlob을 전송하기 위한 예를 업로드합니다.

class MyViewSet(viewsets.ModelViewSet):
    parser_classes = (MultiPartParser, FormParser)
    queryset = MyModel.objects.all().order_by('created_at')
    serializer_class = MySerializer

시리얼라이저:

class MySerializer(serializers.ModelSerializer):
    class Meta:
        model = MyModel
        fields = '__all__'

모델:

class MyModel(models.Model):
    sentence = models.ForeignKey(Sentence, related_name="voice_sentence", on_delete=models.CASCADE)
    voice_record = models.FileField(blank=True, default='')
    created_at = models.DateTimeField(auto_now_add=True)

악리:

export const sendSpeechText = async (audioBlob: any) => {
    const headers = {
        'Content-Type': 'application/json',
        'Content-Disposition': 'attachment; filename=audiofile.webm'
    }

    const audiofile = new File([audioBlob], "audiofile.webm", { type: "audio/webm" })

    const formData = new FormData();
    formData.append("sentence", '1');
    formData.append("voice_record", audiofile);

    return await axios.post(
        SEND_SPEECH_URL,
        formData,
        {
            crossDomain: true,
            headers: headers
        },
    )
}

메모: formData의 voice_record는 모델 내에서 동일해야 합니다.

drf에서 파일을 업로드하는 방법은 크게 3가지입니다.

제목 및 로고 필드가 있는 태그 모델과 TagSerializer가 있다고 가정합니다.

class Tag(models.Model):
    title = models.CharField(max_length=10, default='')
    file = models.FileField(upload_to='tag/', blank=True, null=True, )


class TagSerializer(rest_serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = '__all__'

상황에 맞게 하나를 선택하시면 됩니다.

1- 시리얼라이저 사용:

class UploadFile(APIView):
    parser_classes = (MultiPartParser, FormParser)

    def post(self, request):

        serializer = TagSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        return Response(serializer.data, status=status.HTTP_200_OK)

2- 쓰기 방법 사용:

def save_file(file: InMemoryUploadedFile, full_path):
    with open(full_path, 'wb+') as f:
        for chunk in file.chunks():
            f.write(chunk)


class UploadFile(APIView):
    parser_classes = (MultiPartParser, FormParser)

    def post(self, request):
        file: InMemoryUploadedFile = request.FILES['file']
        # define file_save_path variable 
        full_path = file_save_path + file.name
        save_file(file, full_path)
        return Response(serializer.data, status=status.HTTP_200_OK)

3- File System Storage 사용:

class UploadFile(APIView):
parser_classes = (MultiPartParser, FormParser)

def post(self, request):
    file: InMemoryUploadedFile = request.FILES['file']
    f = FileSystemStorage()
    # this will save file in MEDIA_ROOT path
    f.save(file.name, file)
    return Response(serializer.data, status=status.HTTP_200_OK)

파일 업로드에 기능 기반 보기를 사용하거나 선호하는 사용자용.

이 가이드는 [Creating Models]> [ views ]> [ Serializers ]> [ URLs ]및 [Postman]에 의한 엔드포인트 테스트]의 완전한 가이드입니다.필요한 경우 코드에 코멘트를 넣었습니다.

# models.py
# Imports 
from django.db import models
import os

def document_path_and_name(instance, filename):
    '''  Change the filename to 'instance_id + document_name '''
    ext = filename.split('.')[-1]
    filename = "%s_%s.%s" % (instance.id, instance.document_name, ext)

    ''' if document_name is 'doucment one' in pdf and id is 1
    then filname will be saved as = 1_document_one.pdf '''

    return os.path.join('files/', filename)

class Document(models.Model):
    # I'm using document_name and id to give the filename that would be save with
    # this using document_path_and_name function.
    # you can modify on your need. 
    document_name = models.CharField(max_length=100)
    file = models.FileField(upload_to=document_path_and_name)

    def __str__(self):
        return self.document_name

여기서 파일 업로드를 검증하는 데 시리얼라이저는 필요 없습니다만, 응답을 시리얼화할 필요가 있는 경우는 필요합니다.이 경우는, 심플한 Read Only Serializer 를 사용해 보겠습니다.

# serializers.py
# imports
from rest_framework import serializers

class DocumentSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    document_name = serializers.CharField(read_only=True)
    file = serializers.URLField(read_only=True)

재,에서api_view 그럼 에는 을 하겠습니다.MultiPartParser데코레이터를 사용하여 POST 요청을 통해 파일을 업로드합니다.는 ★★★★★★★★★★★★★★★★★★★★★★★★.document_name모델을 설정한 대로 파일을 올바르게 업로드 할 수 있는 파일입니다.

# views.py
# imports
from rest_framework.decorators import api_view, parser_classes
from rest_framework.response import Response
from rest_framework.parsers import MultiPartParser
from .models import Document
from .serializers import DocumentSerializer

@api_view(['POST'])
@parser_classes([MultiPartParser])
def upload_document(request, filename, format=None):
    """
    A view that can accept POST requests with .media_type: multipart/form-data content.
    """
    file = request.FILES['file']
    doc = Document.objects.create(document_name=filename, file=file)
    # Do any thing else here
    serializer = DocumentSerializer(doc, many=False)
    return Response(serializer.data)

.document_name할 수 있지만 했습니다.filenameAPI Endpoint "URL" "URL" "URL" "URL" "URL" "URL" "URL" "URL" 입니다.

# imports
from django.urls import path
from .views import upload_document

urlpatterns = [
    path('upload_document/<str:filename>/', upload_document),
]

따라서 Postman을 통해 테스트하려면 다음과 같이 유효한 API 엔드포인트로 이동하십시오.

document_name은 이든 전달할 수 .아래 스크린샷에서 실제 파일 이름이 pdf 형식 이외의 것임을 알 수 있습니다.은 우리 회사의 입니다.document_path_and_nameid_syslog_name으로 합니다.저장 파일명은 다음과 같습니다.1_filename.pdf

여기에 이미지 설명 입력

이제 요청만 하면 파일이 다이렉트 파일 스토리지 경로에 업로드됩니다."DocumentSerializer" "JSON Response" "DocumentSerializer" 입니다.는 '파일 업로드'입니다.MultiPartParser데코레이터자세한 내용은 문서를 참조하십시오.

ViewSets를 사용하는 경우 파일 업로드를 처리하는 사용자 지정 작업을 추가할 수 있습니다.

from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.parsers import FileUploadParser
from rest_framework import viewsets
...

class SomeViewSet(viewsets.ModelViewSet):
    serializer_class = ...
    permission_classes = [...]
    queryset = ...

    @action(methods=['put'], detail=True, parser_classes=[FileUploadParser])
    def upload_file(self, request, pk=None):
        obj = self.get_object()
        obj.file = request.data['file']
        obj.save()
        return Response(status=204)

[ View Set ]를 선택합니다.api/item/32/upload_file/.

를 사용하는 이유FileUploadParser멀티 파트와 같은 다른 옵션과는 달리 멀티 파트 인코더에 의존하지 않고 네이티브 앱에서 업로드하는 경우입니다.

언급URL : https://stackoverflow.com/questions/20473572/django-rest-framework-file-upload

반응형