Django REST framework serializer.is_valid() сохраняет файлы в MEDIA_ROOT, хотя значение .is_valid() равно False

У меня есть проект, который поддерживает загрузку файлов через Django forms, а также Django REST framework, эти файлы используются и хранятся в модели 'Document'. Проблема заключается в том, что при загрузке файла, не прошедшего проверку, через REST-фреймворк, файл сохраняется в параметр 'upload_to' (MEDIA_ROOT) (экземпляр модели 'Document' не создается, как и ожидалось), этого не происходит при загрузке того же файла через Django-формы.

Некоторые тесты указывают на то, что "serializer.is_valid()" является тем, что сохраняет файл, несмотря на то, что "serializer.is_valid()" является ложным в случае, на который я ссылаюсь.

Мой идеальный результат заключается в том, что когда неприемлемый файл загружается через REST-фреймворк, этот файл не присутствует в папке MEDIA_ROOT.

Пожалуйста, оставьте ответ/комментарий, если у вас есть какие-либо советы.

Мой код приведен ниже.

Models.py:

from django.db import models
from apps.common.models import BaseModel
from datetime import datetime
import os
from django.core.exceptions import ValidationError


def file_storage_handler() -> str:
    """This function provides a file path to a Document model's FileField based on the current date. If the file path doesn't exist it creates it."""
    currentDate = datetime.now().date()
    path = f"uploaded_documents/{currentDate.year}/{currentDate.month}/{currentDate.day}/"
    if not os.path.exists("media/"+path):
        os.makedirs("media/"+path)
    return path


def validate_file(file): # I dont believe that the specifics in this validator are important
    fileType = file.name.split('.')[-1]
    if not fileType in ['pdf','jpeg','jpg','png','bmp','tiff','heif']:
        raise ValidationError(f"The .{fileType} file type is not supported")


class Document(BaseModel): # Note BaseModel is not a factor
    file = models.FileField(upload_to=file_storage_handler(), validators=[validate_file])
    document_type = models.ForeignKey(DocumentType, on_delete=models.PROTECT) # not important

views.py:

# Document Endpoints
@api_view(["GET","POST"])
@parser_classes([MultiPartParser, FormParser])
def documents_general(request):
    if request.method == "GET":
        #some code, not important
    elif request.method == "POST":
        serializer = DocumentSerializer(data=request.data)
        if serializer.is_valid(raise_exception=True): # I think that this line causes the file to save to the MEDIA_ROOT
            documentObject = serializer.save()
            on_upload.delay(documentObject.id)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Serializer.py:

class DocumentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Document
        fields = '__all__'

    def update(self, instance, validated_data): # TBH IDK why this is here, likely not important
        """This method is called when the serializer is saved, here I am updating the fields which should be updated."""
        instance.document_type = validated_data.get('document_type', instance.document_type)
        instance.save()
        return instance

forms.py: (вероятность не важна)

class DocumentForm(forms.ModelForm):
    class Meta:
        model = Document
        fields = ["file", "document_type"]

Пожалуйста, дайте мне знать, если у вас есть совет или вопросы.

DRF обрабатывает файл до проверки сериализатором, поэтому файл оказывается в MEDIA_ROOT, хотя serializer.is_valid() возвращает False

Если вы хотите удалить файл, вы можете переопределить run_validators в вашем DocumentSerializer следующим образом

from rest_framework import serializers
import os
from django.core.files.uploadedfile import TemporaryUploadedFile, InMemoryUploadedFile

class DocumentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Document
        fields = '__all__'

    def run_validators(self, value):
        try:
            super().run_validators(value)
        except serializers.ValidationError:
            if isinstance(value, TemporaryUploadedFile):
                file_path = value.temporary_file_path()
                if os.path.exists(file_path):
                    os.remove(file_path)
            elif isinstance(value, InMemoryUploadedFile):
                # it is safer to use InMemoryUploadedFile because TemporaryUploadedFile not guaranteed to be present on all file objects
                value.close()
            raise
Вернуться на верх