Why is my CSRF token failing in Django? - python

I've provided CSRF in views.py and included csrf_token in templates, but still search is not working due to “csrf_token failure”.
My views.py code is:
args = {}
args.update(csrf(request))
args['articles']= Article.objects.all()
args['lang'] = language
args['session_language']=session_language
return render_to_response('articles.html', args)
and template code is
<h3>Search</h3>
{% csrf_token %}
<input type='text' id='search' name='search' />

The csrf_token is just the string that is required, you need to do something with it. For starters, capturing it within your template in script takes will mean javascript is "aware" of it.
{# Place this somewhere in your template #}
<script type="text/javascript">
var csrf_token = "{{ csrf_token }}";
</script>
After this, how you submit the AJAX request is up to you, but you can now use this as part of your POST submission.

You'll need to pass the csrf token value in every POST request made.

Related

Django. CSRF token missing or incorrect

I have just recently started learning Django.
I have a problem with the password change page
403
Reason given for failure:
CSRF token missing or incorrect.
My users/urls.py
urlpatterns = [
path(
'logout/',
LogoutView.as_view(template_name='users/logged_out.html'),
name='logout'
),
path(
'login/',
LoginView.as_view(template_name='users/login.html'),
name='login'
),
path(
'password_change/',
PasswordChangeView.as_view(template_name='users/password_change_form.html'),
name='password_change_form'
),
path(
'password_change/done/',
PasswordChangeDoneView.as_view(template_name='users/password_change_done.html'),
name='password_change_done'
),
...,
]
And My Form in Template starts
<form method="post"
{% if action_url %}
action="{% url action_url %}"
{% endif %}
>
{% csrf_token %}
<input type="hidden" name="csrfmiddlewaretoken" value="">
With this form, I get the error 403 and "CSRF token missing or incorrect."
Without this string everythink works
<input type="hidden" name="csrfmiddlewaretoken" value="">
everythink works.
1)Could you please explain me why? And what is it?
What is the best way to use csrf?
2) I also used to write like
<form method="post" action="{% url 'users:password_change_form' %}">
But founded this example using action_url.
What is action_url?
What way is better?
action is the attribute in the form tag. and "action_url" is the URL(a page) it goes to when you click on submit button. So you need to define that URL there. and the correct syntax in Django is :
<form action={% url 'process' %} method="POST">
So here process is name of that URL you define in urls.py file.
Something like this :
path('process/', views.process, name='process')
And in order to work you need to have that file in your app.
So in your case type the name of your URL you've defined in ulrs.py file in if condition.
Try to use only:
{% csrf_token %}
instead of
{% csrf_token %}
<input type="hidden" name="csrfmiddlewaretoken" value="">
I'm afraid that the second line of code overwritten the csrf_token value.
'action' in the form specifies where to send the form-data when a form is submitted. In this case, after the form is submitted, it will go to 'users' app, url name 'password_change_form', then pass to the view associated with it.

How do I submit a form without page reload using Ajax

I'm learning Ajax on how I can submit a comment form without page reload. I'm using Django, I have list of posts in homepage each with comment form. When I submit a comment it is not saving in database and also it doesn't display in browser. When I check on Chrome console, I got an error 2 elements with non-unique id.
from django.http import JsonResponse
from django.template.loader import render_to_string
def home(request):
all_images = Post.objects.filter(poster_profile=request.user)
if request.method == 'POST':
post_id = request.POST.get("post_comment")
post_obj = Post.objects.get(pk=post_id)
form = CommentForm(request.POST)
if form.is_valid():
comment=form.save(commit=False)
comment.user=request.user
comment.commented_image=post_obj
comment.save()
else:
form=CommentForm()
context = {'all_images':all_images, 'form':form}
if request.is_ajax():
html=render_to_string('ajax_feeds_comment.html', context, request=request)
return render(request, 'home.html', context)
#home.html
{% for post in all_images %}
<img src="{{ post.image.url }}">
{% for comment in post.comments.all %}
<p>{{ comment.comment_post }}</p>
{% endfor %}
<div class="reload-form">
{% include "ajax_feeds_comments.html" %}
</div>
{% endfor %}
#ajax_feeds_comments.html
<form method="POST" class="feeds-comment" action=".">
{% csrf_token %}
<input type="hidden" value="{{post.id}}" name="post_comment">
<textarea name="comment_post" class="form-control" id="id_comment_post{{post.id}}"></textarea>
<button type="submit" class="btn btn-primary">submit</button>
</form>
<script>
$(document).on('submit', '.feeds-comment', function(event){
event.preventDefault();
console.log($(this).serialize());
$.ajax({
type: 'POST',
url: $(this).attr('action'),
data: $(this).serialize(),
dataType: 'json',
success: function(response){
$('.reload-form').html(response['form']);
},
error: function(rs, e) {
console.log(rs,responseText);
},
});
});
</script>
There are multiple things not correct here:
In your "urls.py" you should not send every request to your views. This is where you get the "favico.ico" error 500 get from. Having no favico is ok, but getting a Error 500 is not.
Check the html code for duplicate id's! These have to be unique.
If you use django variables for html, do it like this: Instead of "{{post.id}}" use: "{{ post.id }}" with spaces around the var.
In the
document.on("submit", "feeds-comment", function(){...})
you're not using the id of that element but it's class name.
Check where the submit is going to. Check Django if the request is being handled. (You see that in the console where Django is running). Also maybe Post a screenshot here!

[Django]How to display a message(correct or incorrect) after submitting the form, without refreshing the page?

I have a made a quiz page, which checks whether the answer of the user is correct or not using a "checkans" function. I want to return a "Correct" message if the answer is correct and an "Incorrect" message if the answer is not correct. Now I can "kind of" do it, but not exactly what I want. Now it returns the message after redirecting to a whole new page, with the Question Box and everything else totally disappeared, only with the message.
I want the message to be shown on the same original question page, somewhere under the question box or within the question box, without redirecting to another page or refreshing the page, after submitting the answer. I don't know how to do it.
Here is my view:
class QuizView(generic.ListView):
template_name = 'geniusdennis/quiz.html'
queryset = Spanish.objects.all()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# grab the max id in the database
max_id = Spanish.objects.order_by('-id')[0].id
random_id = random.randint(1, max_id + 1)
random_spanish_question = Spanish.objects.filter(id__gte=random_id)[0]
context['random_spanish_question'] = random_spanish_question
return context
Here is my function for checking the answer:
def checkans(request, spanish_id):
random_spanish_question = get_object_or_404(Spanish, pk=spanish_id)
query = request.GET.get('ans')
coreng = random_spanish_question.english_set.get()
if query == str(coreng):
return render(request, 'geniusdennis/quiz.html',{
'message': "Correct!",
})
else:
return render(request, 'geniusdennis/quiz.html', {
'message': "Incorrect.",
'correct_answer': "The correct answer is " + str(coreng),
})
And here is my HTML page:
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'geniusdennis/style.css' %}">
{% if random_spanish_question %}
<div class="flexcontainer" style="justify-content: center;">
<div class="sectiontitle">Quiz time
</div>
<div class="question_card">
<div class="question_word">{{ random_spanish_question }}</div>
<form action="/checkans/{{random_spanish_question.id}}/" method="get">{% csrf_token %}
<label for="ans">Answer:</label>
<input type="text" name="ans"/>
<input type="submit" value="Submit"/>
</form>
<input type="submit" value="Skip"/>
</div>
</div>
{% else %}
{% if message %}
<div class="message">
{{ message }}
</div>
<div class="ans">
{{ correct_answer }}
</div>
{% endif %}
{% endif %}
What you need is ajax, so you need some js code here.
<scrip src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>
$('form').on('submit', function(e) { // or you can get the form by id if you set it
e.preventDefault(); // avoid to execute the actual submit of the form.
var form = $(this);
var url = form.attr('action');
$.ajax({
type: 'GET',
url: url,
data: form.serialize(), // serializes the forms elements.
success: function(data)
{
... // whatever you want to do
var alertMessage = data.message;
if (data.correct_answer) {
alertMessage += ' ' + data.correct_answer;
}
alert(alertMessage); // show response
}
});
});
</script>
html forms will go to action url. If you want some changes or functions in your page without reload, you need to use js.
Quite commonly in web applications, you need to display a one-time
notification message (also known as “flash message”) to the user after
processing a form or some other types of user input.
For this, Django provides full support for cookie- and session-based
messaging, for both anonymous and authenticated users. The messages
framework allows you to temporarily store messages in one request and
retrieve them for display in a subsequent request (usually the next
one). Every message is tagged with a specific level that determines
its priority (e.g., info, warning, or error).
for implementing messages refer to: https://docs.djangoproject.com/en/1.11/ref/contrib/messages/

Python - Django 2.0 - URL patterns, passing arguments

I am writing a very basic web page in Python which has a text box where a user can type in a username, then hit the Ok button which submits a form using a GET request. The GET passes the username as an argument and searches the auth_user table in the database.
My problem is I am not able to pass the username argument, please help if you can Django 2.0 url patterns
urls.py
app_name = 'just_gains'
urlpatterns = [
path('lifecoaching', views.LifeCoach, name='life_coaching'),
path('lifecoaching/resultslifecoaching/<str:user_name>', views.LifeCoachSearchResults, name='results_life_coaching'),
]
forms.py
class LifeCoachSearch(forms.Form):
user_name = forms.CharField(label='Username', max_length=100, required = False)
views.py
def LifeCoach(request):
if request == 'GET':
form = LifeCoachSearch(request.GET)
if form.is_valid:
user_name = form.cleaned_data['user_name']
LifeCoachSearchResults(request,user_name)
else:
form = LifeCoachSearch()
return render(request, 'just_gains/life_coaching.html', {'form': form})
def LifeCoachSearchResults(request, user_name):
testUser = User.objects.filter(username__startswith=user_name)
context = {'TestUser': testUser}
return render(request, 'just_gains/results_life_coaching.html', context)
HTML (lifecoaching)
<form action="{% url 'just_gains:results_life_coaching' %}" method="GET" >
{% csrf_token %}
{{ form }}
<input type="submit" value="OK">
</form>
HTML (resultslifecoaching)
<ul>
<li><a>print usernames that match the argument</a></li>
</ul>
Forgive me for the short response as I am on mobile. Try passing your username as a string in the path using <str:user_name>
Usually I think the form should submit via POST rather than GET, and the value of the submitted username would then be available in the dictionary request.POST['username']. GET should be used to get forms from the server; POST posts information back to the server. POST ensures that the browser bundles everything in the form and sends it complete, but GET tries to encode it in the URL and makes no guarantees.
Using forms, its helpful to have the View divide so that GET requests pull up blank or prepopulated forms (the empty search box) and POST requests are processed and redirected to the parameterized results screen you have.
You would then create a httpRedirect to re-assign the request to your URL with a parameter. I think this link, example 2 is the right way to go.
https://docs.djangoproject.com/en/2.0/topics/http/shortcuts/#redirect
So your function would look like:
def LifeCoach(request):
if request.method = 'GET':
return render(request, 'just_gains/life_coaching.html', context)
elif request.method = 'POST':
# I have skipped form validation here for brevity
return redirect('results_life_coaching',request.POST['username'])
It's possible that having a field called username may clash with or confuse you later when using request.USER['username']. Don't forget to change your form html! All the best!
[Edit 1] My code was wrong; GET should call the lifecoaching form, POST should redirect to the results_life_coaching page.
[Edit 2] My suggestions for your templates:
HTML (lifecoaching.html)
<form action="{% url 'just_gains:life_coaching' %}" method="POST" >
{% csrf_token %}
{{ form }}
<input type="submit" value="OK">
</form>
HTML (resultslifecoaching.html)
<ul>
{% for item in username_list %}
<li>{{item.user_name}} - {{item.achievement}} </li>
{% endfor %}
</ul>

Method Not Allowed The method is not allowed for the requested URL. on DELETE Method Flask

I'm trying to write a delete method for the Flask tutorial app, Flaskr. So far I've been able to set up a delete method and modify my html to access it, but when I try to use it, I receive an error saying "Method Not Allowed The method is not allowed for the requested URL."
Here's my method
#app.route('/delete', methods=['DELETE'])
def delete_entry():
if not session.get('logged_in'):
abort(401)
g.db.execute('delete from entries')
g.db.commit()
flash('Entry was successfully deleted')
return redirect(url_for('show_entries'))
Here's my HTML file
{% extends "layout.html" %}
{% block body %}
{% if session.logged_in %}
<form action="{{ url_for('add_entry') }}" method=post class=add-entry>
<dl>
<dt>Title:
<dd><input type=text size=30 name=title>
<dt>Text:
<dd><textarea name=text rows=5 cols=40></textarea>
<dd><input type=submit value=Share>
</dl>
</form>
{% endif %}
<ul class=entries>
{% for entry in entries %}
<li><h2>{{ entry.title }}</h2>{{ entry.text|safe }}
<form action="{{ url_for('delete_entry') }}" method=delete class=delete_entry>
<input type="submit" value="Delete entry" />
</form>
{% else %}
<li><em>Unbelievable. No entries here so far</em>
{% endfor %}
</ul>
{% endblock %}
I also know that problem :)
In this SO question or here it is explained that the method field of an html <form> only accepts GET and POST as valid values. You are giving it the value DELETE. I suppose that it will fall back to any of the other valid values.
You can indeed verify which method is actually used in your flask log.
Because of the falling back your view at /delete will be accessed using a method which is not present in the methods parameter.
There are two ways to work around this.
Make the view accessible by GET or POST. This is the worse of the two options because a GET request should not have any side effects and it is not RESTful
Instead of using the "built-in" html form you can use an ajax request.
For the second option you would register an event handler for your form button using jQuery.
$("#delete_btn").click(function(){
// send ajax request here
return false; // prevent the form from submitting
}
where delete_btn would be the id for you submit button.
<input id="delete_btn" value="Delete entry">
For the actual ajax request use the ajax method from jQuery ( see the docs )
$.ajax({
url: "your delete url",
method: "DELETE",
})
You can also register a callback in the ajax method to reload the page on success and display a warning when it fails or whatever you want.
And please don't fill in the url for the ajax request by using the url_for function. This will unnecessarily couple the javascript to your html. You should instead write it into a custom data attribute of the submit button and read that attribute with jQuery. Like it is done here

Categories