4

I'm not sure if somehow the directory is wrong or there's just some kind of common mistake in my code, but I just am not able to save my uploaded file to a folder, or more specifically, the media folder as demonstrated in a lot of examples.

I'm just taking a text field and the file and saving it in the DB using Ajax, and it works too, except that whatever file I'm selecting, it's not getting saved in the media folder even if I create one manually nor is it creating one on its own either. I can get this to work without Ajax but not with it. Maybe it's something related to how I'm sending and handling data over Ajax, but I've gone through tons of forums to try and fix it but no results so far. I've double checked everything else such as the settings.py config and the libraries that I've imported, everything looks to be in order. I'm sharing the code below.

index.html

<body>
<div class="container-fluid">
    <div class="col-md-4">
        <form id="data" enctype="multipart/form-data">
            <label for="docn">
                <input type="text" id="docn" placeholder="Please enter document name">
            </label>

            <label for="docc">
                <input type="file" id="doc" name="docu">
            </label>

            <button type="button" onclick="enterdata()">Submit</button>

        </form>
    </div>
</div>
<script>
    function enterdata() {
        var token = '{{ csrf_token }}';
        alert('csrf generated');

        $.ajax({
            type: 'POST',
            url: '/user',
            data: {
                dcn: $('#docn').val(),
                dc: $('#doc').val(),
            },
            headers: {'X-CSRFToken': token},
            success: function () {
                alert("Added");
            }
        })

    }
</script>
</body>

views.py

from django.shortcuts import render
from django.http import HttpResponse
from fileup.models import *
from django.core.files.storage import FileSystemStorage

def insert(request):
    return render(request, 'index.html')

def testing_data(request):
    if request.method == 'POST':
        dcn1 = request.POST['dcn']
        dc = request.POST['dc']

        request_file = request.FILES['docu'] if 'docu' in request.FILES else None
        if request_file:
            fs = FileSystemStorage()
            file = fs.save(request_file.name, request_file)
            fileurl = fs.url(file)

        FileDB.objects.create(
            docname=dcn1,
            doc=dc,
        )

        return HttpResponse('')

urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', insert),
    path('user', testing_data),
]
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root = settings.MEDIA_ROOT)

models.py

from django.db import models

class FileDB(models.Model):
    docname = models.CharField(max_length=255)
    doc = models.FileField()

settings.py config

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

That's the complete project. The end goal is to save the path and filename in the DB with the selected file uploaded in the media folder. The former is being done but with no positive results from the latter.

Thank you.

  • Related question: https://stackoverflow.com/questions/5392344/sending-multipart-formdata-with-jquery-ajax – datosula Dec 02 '20 at 09:07

3 Answers3

1

You say everything works correctly except the storage location of the file. The following code will store uploaded files under /media/photos regardless of what your MEDIA_ROOT setting is:

from django.core.files.storage import FileSystemStorage
from django.db import models

fs = FileSystemStorage(location='/media/photos')

class Car(models.Model):
    ...
    photo = models.ImageField(storage=fs) 

Hope this helps you. Courtesy of Django Doc: https://docs.djangoproject.com/en/3.1/topics/files/

Aadesh Dhakal
  • 412
  • 6
  • 17
  • Technically yes, everything else is working but I should have been more specific. The whole process of uploading isn't working. The field string and file path is being saved in the DB but I debugged and found out that the file itself isn't being passed from the from to the backend, so the problem lies in my handling of the data with ajax. – Bilal Hakim Dec 03 '20 at 08:55
  • Thanks, I was able to make it work, partly because of your answer. – Bilal Hakim Dec 04 '20 at 06:37
1

I've managed to make it work, finally. Sharing the code here for anyone else who's stuck with this issue.

index.html

<body>
<div class="container-fluid">
    <div class="col-md-4">
        <form id="data">
            <label for="docn">
                <input type="text" id="docn" placeholder="Please enter document name">
            </label>

            <label for="docc">
                <input type="file" id="doc" name="docu">
            </label>

            <button type="button" onclick="enterdata()">Submit</button>

        </form>
    </div>
</div>
<script>
    function enterdata() {

        var data1 = new FormData()
        data1.append('dcn', $('#docn').val())
        data1.append('dc', $('#doc').val())
        data1.append('docf', $('#doc')[0].files[0])

        var token = '{{ csrf_token }}';
        alert('csrf generated');

        $.ajax({
            type: 'POST',
            url: '/user',
            data: data1,
            processData: false,
            contentType: false,
            headers: {'X-CSRFToken': token},
            success: function () {
                alert("Added");
            }
        })

    }
</script>
</body>

views.py

from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from fileup.models import *
from django.core.files.storage import FileSystemStorage


def insert(request):
    return render(request, 'index.html')


def testing_data(request):
    if request.method == 'POST':
        dcn1 = request.POST['dcn']
        dc = request.POST['dc']

        upload_file = request.FILES['docf']
        fs = FileSystemStorage()
        fs.save(upload_file.name, upload_file)


        FileDB.objects.create(
            docname=dcn1,
            doc=dc,
        )

        return HttpResponse('')


urls.py

from django.contrib import admin
from django.urls import path
from fileup.views import *
from django.conf.urls.static import static
from django.conf import settings

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', insert),
    path('user', testing_data),
]
if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

settings.py config

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

Now, the media directory is being created upon file upload and files are being saved inside it.

  • Glad that it worked out for you. It would be great if you can specifically mention which part of the code you changed, and why. – ha-neul Dec 05 '20 at 01:39
  • @ha-neul the problem was apparently with ajax, but just because I couldn't get it to work. There must be a way to achieve it through ajax but I haven't figured it out yet. How I did it is by just making a FormData() which acts as the form is being passed through like how you would pass a normal form with a submit button, it uses the same enctype too (you can see it in the function enterdata()). I did that and added processData and contentData as False to prevent it from being converted to a string. – Bilal Hakim Dec 07 '20 at 04:05
0

You are not doing it a right way, you should supply FormData in your Ajax call. see below:

function upload(event) {
event.preventDefault();
var data = new FormData($('form').get(0));

$.ajax({
    url: 'user/',
    type: 'POST,
    data: data,
    cache: false,
    processData: false,
    contentType: false,
    success: function(data) {
        alert('success');
    }
});
return false;
}

$(function() {
    $('form').submit(upload);
});

and in your view you should get the file from request.FILE like below:

def testing_data(request):
    if request.method == 'POST':
        form = FileUploadForm(data=request.POST, files=request.FILES)
        if form.is_valid():
            print 'valid form'
        else:
            print 'invalid form'
            print form.errors
    return HttpResponseRedirect('/')
Shahid Tariq
  • 886
  • 6
  • 19
  • A couple of questions regarding this, please correct me if I'm wrong: 1. since I'm not using a "submit" type button, the preventdefault function is useless, right? I'm just simply calling an onclick function (that has my Ajax) from my button. 2. With the code that you've provided, it's being assumed that I'm using Django's forms, right? I'm actually not using them, as you can see in the code above. I'm assuming you meant to write "UploadFileForm" but even with that, I'd have to import the forms class from forms.py which, again, I'm not using in this project. Thank you. – Bilal Hakim Dec 02 '20 at 10:06
  • Here's the document I'm referring to by the way: https://docs.djangoproject.com/en/3.1/topics/http/file-uploads/ – Bilal Hakim Dec 02 '20 at 10:09