Reputation: 626
I have a Django web application and I'm trying to make an ajax call for uploading a large image. If I can upload the image I am trying to upload, I'll read the image with the pythonocc library and return the volume information. Since this process takes a long time, I am trying to do it using the django-background-tasks library. According to what I'm talking about, the ajax request that I am trying to take the image and send it to the view is as follows.
var data = new FormData();
var img = $('#id_Volume')[0].files[0];
data.append('img', img);
data.append('csrfmiddlewaretoken', '{{ csrf_token }}');
$.ajax({
method: 'POST',
url: '{% url 'data:upload' %}',
cache: false,
processData: false,
contentType: false,
type: 'POST',
data: data,
}).done(function(data) {
});
my view that will work after Ajax request;
def uploadFile(request):
if request.method == 'POST':
file = request.FILES.get('img')
filename = file.name
key = 'media/' + filename
s3_resource = boto3.resource('s3')
bucket = s3_resource.Bucket('bucket')
bucket.put_object(Key=key, Body=file)
new_data = Data(author=request.user)
new_data.save()
data_id = new_data.id
initial = CompletedTask.objects.filter(verbose_name=verbose)
request.session['u_initial'] = len(initial)
verbose = str(request.user) + '_3D'
read_3D(data_id, key, filename, verbose_name = verbose) ###background-task function is called
return redirect('data:uploadStatus')
The view that calls this background task function should also redirect the view, which will show the status of the upload.
def upload_status(request):
customer= str(request.user)
verbose = customer + '_3D'
initial = request.session['u_initial']
if request.is_ajax():
running, completed = get_upload_status(verbose)
context = {
"initial": initial,
"running": running,
"completed": completed,
}
return JsonResponse(context)
return render(request, "file_pending.html")
However, when I made the Ajax request, the view gave The view data.views.uploadFile didn't return an HttpResponse object. It returned None instead.
error because it doesn't enter if request.method == 'POST'
condition. When I remove that condition line from view, it cannot get the img file. By the way, this uploadFile view was working without any problems. Strangely, when I added the upload_status view and redirect it, it stopped working. To revert, I deleted that part and reverted it back, but it still didn't work.
How can I fix this problem? Am I missing something?
Upvotes: 0
Views: 562
Reputation: 16666
A. You should restrict your view method to the actual method you are expecting using the require_http_methods decorator
from django.views.decorators.http import require_POST
@require_POST
def uploadFile(request):
file = request.FILES.get('img')
filename = file.name
key = 'media/' + filename
s3_resource = boto3.resource('s3')
# ....
return redirect('data:uploadStatus')
That way calls to this endpoint not using POST will receive a 405 Method not allowed response. It's easier to debug and clarifies what is going wrong.
B. Make sure that your Ajax call in the frontend follows the redirect.
The cache
parameter is not necessary with POST (unless you plan for IE8)
About contentType=false
and processData=false
: it still looks to me like this is a regular multipart-formdata call. Don't do this unless you know why you are doing it. Your Django code looks like it will handle the regular form data just fine, no need to tinker with the default behaviour.
C. You have to implement an error callback, as well:
}).done(function(data) {
}).fail(function(xhr, text, error) {
console.log(text, error)
});
I suppose what happens is some error that you are not handling in the JS code.
You have not added your settings, so I cannot be sure, but I suppose that you have not setup your CSRF configuration for AJAX correctly. One way to fix this would be to add the CSRF cookie to the AJAX request, as well. Both the CSRF form field as well as the cookie have to be present.
See https://docs.djangoproject.com/en/3.1/ref/csrf/#ajax
Upvotes: 2