I got a 500 error page which has a form, however the CSRF token is not generated when 500 error page is thrown. What's the best way to generate the CSRF token on a 500 error page to make the form post work? Should I just define my own custom 500 error view?
OK, I tried defining the custom 500 view and worked, for anyone who has the same issue, here it's how:
define a custom 500 error view
from django.shortcuts import render
def server_error(request):
vars = {}
return render(request, '500.html', vars, status=500)
then in the main urls.py add:
handler500 = 'your_app.views.errors.server_error'
You have to pass the token on the ajax request
var data = {
errorresponse: errorresponse,
'csrfmiddlewaretoken': '{{ csrf_token }}',
}
$.ajax({
type: "POST",
url: "/your-target-url/",
data: data, // this passes data context into view
success: function(data) {
Related
I am working on this CS50W project.
When using the fetch API to send POST requests to the server, everything worked fine.
After I changed the method to PUT, or any other unsafe methods, things stopped working.
Javascript
let like_form = document.querySelector('#like-form');
let data = new FormData(like_form);
fetch(`post/${post_id}/like`, {
method: 'POST',
body: data,
credentials: "same-origin"
})
views.py
#login_required
def like_post(request, post_id):
if request.method == 'POST':
post = get_post(post_id)
if post:
if request.user in post.liked_by.all():
post.liked_by.remove(request.user)
status = False
else:
post.liked_by.add(request.user)
status = True
return JsonResponse({
'message': 'Success.',
'status': status
}, status=200)
index.html
<form id='like-form'>
{% csrf_token %}
</form>
Output using POST
{message: 'Success.', status: false}
Output using PUT
PUT http://127.0.0.1:8000/post/17/like 403 (Forbidden)
Forbidden (CSRF token missing.): /post/17/like
The only thing I changed was the method in fetch and views.py
Any help will be appreciated.
After going into the source code, I found out that for PUT, the csrf_token is read from the headers of the request instead of the body. Therefore adding
headers: {
'x-csrftoken': CSRF_TOKEN_ELEMENT.value
}
solved the problem
Whenever I am logged into a django user and I try and send a PUT request to my URL I get a 403 Forbidden Error. However, it works both when I am not logged in and also from the Django Rest API client.
Here is my code in my frontend:
let parameters = `user/${userID}/`
return new Promise((resolve, reject) => {
axios({
method: 'PUT',
url: 'http://127.0.0.1:8000/' + parameters,
data: updatedUser,
headers: {
'Content-Type': 'application/json',
},
})
.then((response) => {
resolve(response)
})
.catch(error => {
console.log(error)
// reject(error)
})
});
I am very confused as I can't see the difference when I am logged into a django user and when I am not, as nothing changes in the frontend. Thanks
EDIT:
This is in my urls.py
path('user/<id>/', views.RetrieveUpdateDestroyUser.as_view()),
And this is the view:
class RetrieveUpdateDestroyUser(RetrieveUpdateDestroyAPIView):
"""
View to handle the retrieving, updating and destroying of a User.
This View will also log any changes made to the model.
"""
serializer_class = UserCreateUpdateSerializer
queryset = CustomUser.objects.all()
lookup_field = 'id'
permission_classes = (AllowAny,)
def update(self, request, *args, **kwargs):
"""
PUT and UPDATE requests handled by this method.
"""
return super().update(request, *args, **kwargs)
I have also tested doing POST and PUT when I am logged into a user and they don't work, but GET does. Thanks
Also tried disabled CSRF but to no avail either
Writing this answer to summarize what we have discovered.
The problem: the AJAX (PUT) call to the DRF endpoint fails with 403 HTTP error for authenticated users and works just fine for anonymous users
Desired Behaviour: make that call working for both anonymous and authenticated users
Reason: by default DRF perform CSRF check for unsafe HTTP methods (POST, PUT, PATCH and DELETE) https://www.django-rest-framework.org/topics/ajax-csrf-cors/
Possible Solutions:
Disable CSRF check like described here https://stackoverflow.com/a/30875830/764182
Pass CSRF token within the PUT request. For more information about CSRF + AJAX in Django read here https://docs.djangoproject.com/en/3.1/ref/csrf/#ajax. For Axios and default Django settings the solution might be:
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.xsrfCookieName = "csrftoken";
axios.defaults.withCredentials = true;
I have a complex problem in sending and receiving data in react to django with axios.
I'm not using REST API. This is my Handel function which is related with my signup form tag and after each click on submit button this function executes:
HandelSignUp(e){
e.preventDefault();
let Username = this.refs.username.value;
let Pass = this.refs.pass.value;
let Email =this.refs.email.value;
axios({
url:'http://127.0.0.1:8000/signupAuth/',
mothod:'post',
data:{
username:this.Username,
pass:this.Pass,
email:this.Email
},
headers: {
"X-CSRFToken": window.CSRF_TOKEN,
"content-type": "application/json"
}
}).then(respons =>{
console.log(respons);
})
.catch(err =>{
console.log(err);
});
and also this is my django urls.py :
urlpatterns = [
path('signupAuth/',ReactApp_View.signupRes),
]
ReactApp_View is my views.py in ReactApp file which I imported correctly.
ok now let's see my views.py:
def signupRes(request):
body_unicode = request.body.decode('utf-8')
data = json.loads(myjson)
return HttpResponse(request.body)
after all when I fill my signup fields and then click on button I see this massage in console log of my browser:
Failed to load http://127.0.0.1:8000/signupAuth/: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access.
What should I do?
and an extra question: what happen in the given url in my axios?
just open your website with the same host url you are trying to call. Use http://127.0.0.1:8000/ instead of localhost
I have an ajax call which sets
request.user.my_field = value
When the ajax succeeds, I reload the page with location.reload(True)
I expect the request.user.my_field in the view function is updated now but it has the old value.
How can I fix this?
EDIT
The ajax call:
$.ajax({
type: 'POST',
url: '{% url editor_select %}',
data: {'editor_type':$(this).val(),
success: function(response_data) {
location.reload(true);
}
}
});
The first view:
def editor_select(request):
"""
called when user changes editor type to post question/answer
"""
editor_type = CharField().clean(request.POST['editor_type'])
request.user.editor_type = editor_type
request.user.save()
The second view:
def second_view(request):
print 'ask, editor_type:', request.user.editor_type
I find AuthenticationMiddleware (which sets request.user to request), doesn't get called in between the ajax call and the location.reload()
so umm???
Save the model before exiting the view.
request.user.save()
Wow shoot me..
success: was inside data and it requested two pages in succession.
I'm trying to perform a simple post to django that will take in a variable and then redirect the user to another page. Right now, my javascript looks like this:
$.ajax({
type: "POST",
url: "{% url unity.survey.views.post %}",
data: { // <-- error here?
'order' : '1',
'csrfmiddlewaretoken': '{{ csrf_token }}'
},
success: function(datas) {
if (datas.redirect) {
window.location.href = data.redirect;
}
}
});
};
My corresponding view in django looks like so:
def post(request, *args, **kwargs):
if 'order' in request.POST:
order = request.POST['order']
else:
return redirect('unity.survey.views.login')
.... some calculations with order ....
return render_to_response(
'template.html',
some_dictionary,
context_instance=RequestContext(request)
)
For some reason, it appears that nothing is sent to the view. Looking at Firefox's web console, I see:
[07:31:12.414] POST http://127.0.0.1/unity/ survey/ [undefined 17ms]
[07:31:12.422] GET http://127.0.0.1/unity/survey/ [HTTP/1.1 302 FOUND 73ms]
[07:31:12.497] GET http://127.0.0.1/unity/survey/login [HTTP/1.1 200 OK 177ms]
It just redirects me to the login page regardless of what I do. I've tried using .post instead of .ajax, but it results in the same thing. Any idea why this might be the case? I have a similar function and it works great but for some reason I can't get this to work. It just appears as if no POST data is being sent.