Reputation: 13
I'm currently learning in Django, and in this fetch request, I always get the same error. How could I avoid it?
topup.html
let data = new FormData();
data.append('amount', document.getElementById('amount').value);
data.append('csrfmiddlewaretoken', "{{ csrf_token }}");
var response = fetch('{% url "secret" %}', {
method: 'POST',
body: data,
credentials: 'same-origin',
})
views.py
def secret(request):
amount = request.POST["amount"]
error:
MultiValueDictKeyError at /secret
'amount'
Request Method: GET
Request URL: http://127.0.0.1:8000/secret
Django Version: 3.0.6
Exception Type: MultiValueDictKeyError
Exception Value:
'amount'
Exception Location: C:\Users\eric3\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\utils\datastructures.py in getitem, line 78
Python Executable: C:\Users\eric3\AppData\Local\Programs\Python\Python38-32\python.exe
Python Version: 3.8.2
I would really appreciate some help.
Thanks!
Upvotes: 1
Views: 1151
Reputation: 2272
You get MultiValueDictKeyError
exception when opening that URL, because when request.POST["amount"]
is evaluated, it founds no item within the POST dictionary with a key named 'amount'
.
Apparently, you want secret
view to be a view that is going to be reached only through ajax calls, not to be accessed by the user. If you don't want that, to get rid of that exception being raised when non-ajax requests reach the view, then do the following:
def secret(request):
amount = request.POST.get("amount")
# ... all your other code
Now it doesn't matter if your view is accessed by a user or by an ajax call, that exception is gone.
On the other hand, the documentation advises to use the canonical csrf token included in the cookies, when performing POST method requests through ajax. Make sure that you have put 'X-CSRFToken'
within the HTTP request headers to do so.
The JavaScript code should look more or less as follows:
/* Create FormData instance and append the field that you want */
let data = new FormData();
data.append('amount', document.getElementById('amount').value);
/* Perform the fetch call */
fetch("{% url 'secret' %}", {
method: 'POST',
body: data,
headers: {'X-CSRFToken': csrftoken}
})
/* Do whatever you do when a response (successful or not) has been received */
.then(response => {
console.log(response);
})
/* Get csrf cookie */
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
As said in the docs, you can simplify a lot the process of getting the cookie by using the JavaScript Cookie Library
Upvotes: 1