Django. CSRF token missing or incorrect - python

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.

Related

Django can't search "method not allowed"

im new to django and im currently doing a website for my friend. he wants me to make a system where the users can search the database and the website gives the relevent items according to their serial number.
i followed a tutorial from the following site: https://learndjango.com/tutorials/django-search-tutorial to figure out how to do db searchs which helped a lot, but im still having a problem: my search bar works, and the result page also works but it only works when i manually type the query on the searchbar myself (e.x. results/?q=number1). However when i search using the input bar and the submit button it sends me to /results/ page and the page gives this:
This page isn’t working
If the problem continues, contact the site owner.
HTTP ERROR 405
-when i open up pycharm to see the error in terminal it says:
Method Not Allowed (POST): /result/
Method Not Allowed: /result/
[27/Oct/2020 20:06:02] "POST /result/ HTTP/1.1" 405 0
here are my codes(python3.7,pycharm) websites/urls:
from . import views
from django.urls import path
from django.contrib.auth import views as auth_views
urlpatterns = [
path('register/',views.UserFormView.as_view(), name='register'),
path('login/', auth_views.LoginView.as_view(), name='login'),
path('', views.IndexViews.as_view(), name='index'),
path('scan/', views.ScanView.as_view(), name='scan'),
path('result/', views.SearchResultsView.as_view(), name='result'),
]
websites/views:
class IndexViews(generic.ListView):
template_name = "websites/index.html"
context_object_name = "object_list"
def get_queryset(self):
return Website.objects.all()
class ScanView(TemplateView):
form_class = SerialFrom
template_name = 'websites/scan.html'
class SearchResultsView(ListView):
model = SerialNumber
template_name = 'websites/result.html'
def get_queryset(self): # new
query = self.request.GET.get('q')
context = self.get_context_data(object=self.object)
object_list = SerialNumber.objects.filter(
Q(number__iexact=query)
)
return object_list
scan.html:
{% extends 'websites/base.html' %}
{% block albums_active %}active{% endblock %}
{% block body %}
<head>
<meta charset="UTF-8">
<title>Scan</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<form class="box" action="{% url 'result' %}" method="POST">
<h1>Product Check</h1>
<p> Please enter the serial id of your product to check it.</p>
{% csrf_token %}
<input type="text" name="q" placeholder="Serial Number">
<input type="submit" name="q" placeholder="Check">
</form>
</body>
{% endblock %}
thank you for taking your time and reading, please help me i really need to do this.
A ListView [Django-doc] by default does not implement a handler for a POST request. Searching is normally done through a GET request, so you should use:
<form class="box" action="{% url 'result' %}" method="GET">
<h1>Product Check</h1>
<p> Please enter the serial id of your product to check it.</p>
<input type="text" name="q" placeholder="Serial Number">
<input type="submit" placeholder="Check">
</form>
Furthermore the <input type="submit"> should not have a name="q" attribute.
As #Melvyn says, you can also alter the type to type="search" [mozilla] for the text box:
<form class="box" action="{% url 'result' %}" method="GET">
<h1>Product Check</h1>
<p> Please enter the serial id of your product to check it.</p>
<input type="search" name="q" placeholder="Serial Number">
<input type="submit" placeholder="Check">
</form>

Delete an object in Django

I am trying to delete an object. This is the HTML, todo should be deleted when you Click on button (I am trying to call delete_todo) :-
<ul>
{% for all %}
</ul>
This is the views.py,
You need to change few things in your code.
First of all change urlpattern delete_todo you need to add argument, which allows to determine in view what object you want to delete:
url(r'^(?P<todo_id>[0-9]+)/$', views.delete_todo, name='delete_todo'),
Then you need change delete_todo itself:
def delete_todo(request, todo_id):
instance = get_object_or_404(Todo, pk=todo_id)
instance.delete()
return redirect('index')
Here you can use get_object_or_404 fuction to get object with id.
And finally you need to pass url's argument to view from template:
<form action="{% url 'lists:delete_todo' todo_id=todo.id %}" method=post>
<input id="submit" type="button" value="Click" />
</form>
Just to add clarification on the use of the form and csrf: it's necessary in order to ensure that different users of your app can't delete content that isn't theirs.
In your template, you'll need to include the csrf tag as such:
<form method="post" action={% url 'delete_todo' todo_id=todo.id %}>
{% csrf_token %}
<input type="button" id="submit" value="Delete" />
</form>

Django from doesn't get processed. HTTP 405 error raises

I am trying to process a post form, but I can't manage. I have prepared the form, gave the action link, set the method to post, but when I hit the submit button, nothing happens, not even an error page isn't shown by django despite my debug option is True.
Here is the form code in my template file:
<form method="post" action="{% url 'articles:stepprocess' 0 %}">
{% csrf_token %}
<p><label for="title">Title:</label>
<input name="title" id="title" type="text"/></p>
<p>
<label for="dif">Difficulty</label>
<select name="dif" id="dif">
{% if difficulties %}
{% for difficulty in difficulties %}
<option value="{{ difficulty.pk }}">{{ difficulty }}</option>
{% endfor %}
{% endif %}
</select>
</p>
<p><label for="article">Content:</label>
<textarea cols="37" rows="11" name="article" id="article"></textarea></p>
<p><input name="send" style="margin-left: 150px;" class="formbutton" value="Send"
type="submit"/></p>
</form>
My urls.py file:
from django.conf.urls import url
from .views import *
urlpatterns = [
url(r'^$', Index.as_view(), name="index"),
url(r'^new/(?P<step>[0-9]+)/$', NewArticle.as_view(), name="newarticle_continue"),
url(r'^new/', NewArticle.as_view(), name="newarticle"),
url(r'^new/process/(?P<step>[0-9]+)/$', FormManager.as_view(), name='stepprocess')
#url(r'^show/(?P<article>[0-9]+)/$'),
]
And lastly, my views.py file:
#required imports...
class FormManager(View):
def post(self, request, *args, **kwargs):
return HttpResponse(kwargs['step'])
When I hit the submit button, it gives me HTTP 405 error. I can see this error in python console but nothing shows in browser. Just blank white screen.
This was actually to test if view works properly. My final purpose is that I would like to access the post variables and redirect the page. However, HttpResponseRedirect also doesn't work. How can I fix this?
HTTP 405 error means "method not allowed"
In your case you are POSTing... the view looks like it should accept POST requests though.
The problem is your urls.py is wrong, the url you POSTed to is intercepted by the NewArticle view instead, which I guess only accepts GETs.
from django.conf.urls import url
from .views import *
urlpatterns = [
url(r'^$', Index.as_view(), name="index"),
url(r'^new/process/(?P<step>[0-9]+)/$', FormManager.as_view(), name='stepprocess')
url(r'^new/(?P<step>[0-9]+)/$', NewArticle.as_view(), name="newarticle_continue"),
url(r'^new/', NewArticle.as_view(), name="newarticle"),
#url(r'^show/(?P<article>[0-9]+)/$'),
]
Django looks at the urls in the urlconf in the order they are defined and will dispatch your request to the first one that matches.
Above I have modified the order, alternatively you could just add the $ to end of url:
url(r'^new/$', NewArticle.as_view(), name="newarticle"),
this will prevent it matching any new/* url paths.

Django templates not altering form action

I have a URL file chat.urls.py:
`urlpatterns = patterns('',
url(r'^message/(?P<username>\w+)/$',views.message,name='message'),
url(r'^message/(?P<username>\w+)/submit/$',views.send_message,name='send_message'),
url(r'^inbox/$',views.inbox,name='inbox'),
url(r'^inbox/(?P<username>\w+)/$', views.inbox_by_user,name='inbox_by_user'),
)`
and a message.html template to send a message from with a form like this:
<form action="{% url 'inbox' %}" method="post">
{% csrf_token %}
<input type="text" name="text" id="text" value="" />
<label for="message">Enter your message here</label><br />
<input type="submit" value="Send" />
</form>
where I substituted previously working code for "url 'inbox'", and no matter what I substitute for the form action I always get html source rendered as
<form action="/chat/message/[username]/" method="post"...
no matter what. I have restarted the server, made sure I saved changes, and like it has a mind of its own, it's always /chat/message/[username]. When I changed that URL reverse to 'inbox' I should see chat/inbox based on the URLs.
According to the information in comment, you need {% url 'chat:inbox' %} not {% url 'inbox' %} in the form.

Django: Template {% url %} tag, how to pass parameter from form

There is template:
<form action="{% url 'nfoapp.views.kinoscrap' <I WANT MOVIE_ID THERE> selectshort.id %}" method="post">
<input type="text" class="form-control" name="MOVIE_ID">
<button type="submit" class="btn btn-danger">Kinopoisk Search by ID</button>
</form>
There is my urls.py:
(r'^kinoscrap/(?P<kinoid>\d+)/(?P<shortid>\d+)/$', kinoscrap),
I want pass to kinoscrap two parameters - text field from form (MOVIE_ID) and 'selectshort.id' variable. The problem is that i can't put simple MOVIE_ID in first line of template, I got error. But when I try put instead MOVIE_ID other variable, for example selectshort.id, program work without error.
How I can trasmit text field value to view?
p.s I use bootstrap, if it has some importance.
You could have the form action empty, so to the same view, and then in the view redirect using the POST data from the form.
<form action="" method="post">
<input type="text" class="form-control" name="MOVIE_ID">
<button type="submit" class="btn btn-danger">Kinopoisk Search by ID</button>
</form>
And then in the view
def searchView(request):
if request.method == 'POST':
# get variables from form and redirect
else:
# do your normal rendering
(r'^kinoscrap/(?P<kinoid>\d+)/(?P<shortid>\d+)/$', kinoscrap),
Your urls.py accepts to integer values in the url (something like kinnoscrap/12/21), if you pass anything beside integers it'll throw an error. If you want to pass a text field you'll have to change the regular expression.
Try out your regexes at regex101 here to see if they'll work.

Categories