Почему изображения не передаются при использовании ajax вызова в django?

Я использую modelForm для создания объектов поста через ajax. Поле изображений является частью формы, но не передается в поля класса Meta, потому что это позволит сначала сохранить пост, а затем добавить загруженные изображения. Моя проблема в том, что если я использую обычный вид (без ajax), то request.FILES передаются правильно, но когда я использую ajax, то эти файлы не являются частью request.files, что приводит к пустому <MultiValueDict: {}> Я не знаю почему. Вот мой код.

    def post(self, request, *args, **kwargs):
    form = PostForm(request.POST or None, request.FILES or None)
    result = {}
    files = request.FILES
    print(files)
    if is_ajax(request=request) and form.is_valid():
        print("the request is ajax and the form is valid")
        title = form.cleaned_data.get("content", "")
        print("Title ", title)
        post_instance = form.save(commit=False)
        post_instance.author = request.user
        result['success'] = True
        return JsonResponse(result)

         $.ajax({
        url: $("#CreatePostModal").attr("data-url"),
        data:$("#CreatePostModal #createPostForm").serialize(),
        method: "post",
        dataType: "json",
        success: (data) => {
            if (data.success) {
                setTimeout(() => {
                    $(e.target).next().fadeOut();
                    ResetForm('createPostForm', 'PreviewImagesContainer')
                    $("#CreatePostModal").modal('hide')
                    $(e.target.nextElementSibling).fadeOut()
                    alertUser("Post", "has been created successfully!")// alerting the user 
                }, 1000)
                console.log(data.title)
            } else {
                $("#createPostForm").replaceWith(data.formErrors);
                $("#PreviewImagesContainer").html("");
                $("#CreatePostModal").find("form").attr("id", "createPostForm");
                $(e.target.nextElementSibling).fadeOut()
            };

            $(e.target).prop("disabled", false);
        },
        error: (error) => {
            console.log(error)
        }
    })
});

Вот файл формы

class PostForm(forms.ModelForm):
images = forms.ImageField(
    required=False,
    widget=forms.ClearableFileInput(attrs={
        'multiple': True,
    })
)

class Meta:
    model = Post
    fields = ("content",)
    widgets = {
        "content": forms.Textarea(attrs={"placeholder": "Tell us something today....", "rows": 5, "label": ""})
    }

снова поле изображения имеет многотонные отношения с моделью поста. Что я делаю неправильно?

Я наконец решил эту проблему, используя FormData из javascript, перебирая файлы, которые я получаю из ввода, а затем добавляю их к данным FormData.

    let imageFiles = []
$("#CreatePostModal").on('change', (e) => {
    $(postImagesPreviewContainer).html("")
    if ($(e.target).attr("id") !== "id_images") return;
    var filenames = "";
    for (let i = 0; i < e.target.files.length; i++) {
        filenames += (i > 0 ? ", " : "") + e.target.files[i].name;
    }
    e.target.parentNode.querySelector('.custom-file-label').textContent = filenames;

    //why is the this element returning the document and not the target itself
    // check the length of the files to know what template to make
    const files = e.target.files
    const numberOfImages = files.length
    let gridColumnSize;
    if (numberOfImages > 5 | numberOfImages === 0) return;
    var row = document.createElement("div")
    row.setAttribute("class", "post-images")

    for (file of files) {
        
        const postImageChild = document.createElement("div");
        postImageChild.setAttribute("class", "post-images__child_down")
        const reader = new FileReader();
        reader.onload = () => {
            img = document.createElement("img")
            img.setAttribute("src", reader.result)

            img.onload = (e) => {
                // here i will process on resizing the image
                const canvas = document.createElement("canvas")
                const max_width = 680
                const scaleSize = max_width / e.target.width
                canvas.width = max_width
                canvas.height = e.target.height * scaleSize
                var ctx = canvas.getContext("2d") // setting the context of the canvas
                ctx.drawImage(e.target, 0, 0, canvas.width, canvas.height)
                const encodedSource = ctx.canvas.toDataURL(e.target, 'image/png', 1)
                const processedImg = document.createElement("img") // create a processed image and return it.
                processedImg.src = encodedSource
                $(postImageChild).append(processedImg)
                imageFiles.push(processedImg)
            }
        }
        $(row).prepend(postImageChild)
        $(postImagesPreviewContainer).append(row);
        reader.readAsDataURL(file)
    }

После получения и изменения размеров всех изображений я сделал ajax вызов следующим образом:

    $("#CreatePostModal").on("click", (e) => {
    if ($(e.target).attr("id") !== "createPostBtn") return;
    e.preventDefault();
    e.target.setAttribute("disabled", true);
    $(e.target.nextElementSibling).fadeIn()
    var form = $("#createPostForm")[0]
    var data = new FormData(form); // getting the form data
    console.log("this is the data", data)
    for (var i = 0; i < imageFiles.length; i++) { // appending images to data
        data.append('images', imageFiles[i]);
    };

    $.ajax({
        url: $("#CreatePostModal").attr("data-url"),
        data: data, //$("#CreatePostModal #createPostForm").serialize(),
        method: "post",
        processData: false,
        cache: false,
        contentType: false,
        dataType: "json",
        success: (data) => {
            if (data.success) {
                setTimeout(() => {
                    $(e.target).next().fadeOut();
                    ResetForm('createPostForm', 'PreviewImagesContainer')
                    $("#CreatePostModal").modal('hide')
                    $(e.target.nextElementSibling).fadeOut()
                    alertUser("Post", "has been created successfully!")// alerting the user 
                }, 1000)

            } else {
                $("#createPostForm").replaceWith(data.formErrors);
                $("#PreviewImagesContainer").html("");
                $("#CreatePostModal").find("form").attr("id", "createPostForm");
                $(e.target.nextElementSibling).fadeOut()
            };

            $(e.target).prop("disabled", false);
        },
        error: (error) => {
            console.log(error)
        }
    })
});

и, наконец, получение изображений из request.FILES в файле views.py.

    def post(self, request, *args, **kwargs):
    form = PostForm(request.POST or None, request.FILES or None)
    result = {}
    files = request.FILES
    if is_ajax(request=request) and form.is_valid():
        post_obj = form.save(commit=False)
        post_obj.author = request.user
        print(post_obj)
        post_obj.save()
        for file in files:
            new_file = Files(image=file)
            new_file.save()
            post_obj.images.add(new_file)
        post_obj.save()

        result['success'] = True

        return JsonResponse(result)
Вернуться на верх