Django csrf_token forbidden on reload - django

I am new to python and django. I started an online app with user login etc. Everything works as expected. But if I am at a page with the related view having #login_required decorator and I reload the page I get the Forbidden (403) CSRF verification failed. Request aborted. Just by reloading. All of my forms work perfectly as well. Can you tell me how can I fix this?
A view:
#login_required
def main(request):
user=request.user
if request.method=='POST':
projectid=request.POST['project']
project = Project.objects.get(pk=int(projectid))
if project:
change=Change(user=user, project=project,starttime=datetime.now())
change.save()
return render_to_response('ProjectLogging/timer.html', {'change':change}, context_instance=RequestContext(request))
else:
HttpResponse("Choose a valid project!")
HTML:
<div>
<span style="color:red">You have uncommitted changes:</span><br>
<table>
<tr>
<td><b><u>Project</u></b></td>
<td><b><u>Started</u></b></td>
<td><b><u>Finished</u></b></td>
</tr>
{%for f in unfinished_forms%}
<tr>
<td>{{form}}<td>
</tr>
{%endfor%}
</table>
</div>
{%endif%}
<div>
<form action="/main/" method="post" name="project_list">
{%csrf_token%}
{%for p in project_list%}
<input type="radio" name="project" value="{{p.id}}">{{p.title}}<br>
{%endfor%}
<input type="submit" value="Start working!">
</form>
</div>

Related

What can cause MultiValueDictKeyError in Django?

i almost finished my register form, but something went wrong and i totally don't know what. It is a little difficult to describe but i will try.
So, as you can see here is login form:
login.html
<h1>login page</h1>
<table>
<tr>return to register page<br> </tr>
<tr>return to home page </tr>
</table>
<br>
<div>
<form method="post">
{% csrf_token %}
<div>
<div><label>Login/Email </label><input type="text" name="login_name" placeholder="Login/Email"></div>
<div><label>Password </label><input type="password" name="login_password" placeholder="enter password"></div>
<div><input type="submit" value="Login"></div>
</div>
</form>
</div>
and here is register form:
register.html
<h1>Register page</h1>
<table>
<tr>return to login page <br></tr>
<tr>return to home page </tr>
</table>
<br>
<div>
<form method="POST">
{% csrf_token %}
<div>
<div><label>Name </label><input type="text" name="registerFrom_name" placeholder="Enter the name"></div>
<div><label>Surname </label><input type="text" name="registerFrom_surname" placeholder="Enter the surname"></div>
<div><label>Login/Email </label><input type="text" name="registerFrom_login" placeholder="Login/Email"></div>
<div><label>Password </label><input type="registerForm_password" name="registerFrom_password" placeholder="Enter password"></div>
<div><label>Email </label><input type="text" name="registerForm_email"></div>
<div><input type="submit" value="Register"> </div>
</div>
</form>
</div>
Bellow my own backend to handle froms:
view.html
# BACKEND
from django.shortcuts import render
from django.views import View
from . import ValidateUser, RegisterUser
# Create your views here.
CSRF_COOKIE_SECURE = True
class WebServiceView(View):
# INDEX - MAIN PAGE
def indexPage(self, request):
return render(request, "index.html")
def register(self, request):
res = RegisterUser.RegisterUser("user", "user", "login", "test", "emai#email")
res.createUser()
return render(request, "register.html")
def login(self, request):
print("Login function")
res = ValidateUser.ValidateUser('/config/dbConfig.ini', '127.0.0.1') # Connection to mysql database
formParametr = request.POST
print(formParametr)
login = formParametr['register_name']
password = formParametr['register_password']
res.checkUser(login, password.encode("utf8"))
return render(request, "login.html")
Problem rise when i first open register.html and then i will go to the login.html page. Django throw MultiValueDictKeyError at /shop/login.html. I completely don't understand why. As you can see, a key "name" has 'register_name' already. So what can cause problem ?
Below Full error:
'register_name'
Request Method: GET
Request URL: http://127.0.0.1:8000/shop/login.html
Django Version: 2.2.5
Exception Type: MultiValueDictKeyError
Exception Value:
'register_name'
Exception Location: /usr/local/lib/python3.7/dist-packages/django/utils/datastructures.py in __getitem__, line 80
Python Executable: /usr/bin/python3.7
Python Version: 3.7.4
Python Path:
['/home/reg3x/PycharmProjects/lovLevelMusic',
'/usr/lib/python37.zip',
'/usr/lib/python3.7',
'/usr/lib/python3.7/lib-dynload',
'/usr/local/lib/python3.7/dist-packages',
'/usr/lib/python3/dist-packages',
'/usr/lib/python3.7/dist-packages']
It's a KeyError. It's telling you that you don't have a key for register_name in your POST dictionary. And that's because you used login_name in the template.
Really, you should be using Django forms for this, which would a) take care of outputting the fields in the template with the correct names and b) ensure the data was valid and fully populated before you accessed it in the view.
(There are other things in your code that make me very concerned as well. Why have you got login and register methods within a view class? That's not how class-based views work. And why is your URL ending in .html? That's not how Django URLs work. And, most importantly, what is ValidateUser and RegisterUser? Why are you connecting to your database explicitly in each view? Why do you have those classes? That is not how you work with the database in Django. Why are you doing any of this?)

Django is_authenticated and #login_required both not working

I tried to make some pages only visible when logged in.
I tried it with:
def backend(request):
if request.user.is_authenticated:
return render(request, 'web/backend-index.html')
else:
return redirect(reverse('web:login'))
and also with:
#login_required
def backend(request):
return render(request, 'web/backend-index.html')
The first code does not let me log in.
The second code does not let me log in but the url changes too:
http://127.0.0.1:8000/login/?next=/backend/
If I just render the view without checking if logged in, the login is working fine and I´ll be passed to the backend page.
The whole code is on github: https://github.com/psmaster1/BrainSystems/tree/master/smarthome/web
I don't get any error messages. It's just redirecting to the login page...
Your login form is incorrect - that's why you never actually authenticate. It was sending POST request to incorrect endpoint and it was not rendering actual form. This is how you can render fields manually
Change it to this:
<section class="login-form">
<div class="login-fields">
<h3>Login</h3>
<form method="POST">
{% csrf_token %}
<div class="form-group">
{{ login_form.username }}
<label for="{{ login_form.username.id_for_label }}" class="control-label">Username</label><i class="bar"></i>
{{ login_form.username.errors }}
</div>
<div class="form-group">
{{ login_form.password }}
<label for="{{ login_form.password.id_for_label }}" class="control-label">Passwort</label><i class="bar"></i>
{{ login_form.password.errors }}
</div>
<div class="button-container">
<input type="submit" class="button" value="Login" />
</div>
</form>
<p>Noch nicht Registriert?</p>
Registrieren
</div>
</section>
Already fixed it! The Problem was the action attribute in the form tag. It causes the troubles. Just removed it from the form tag and make a redirect in the login() method. Thanks guys! :)

Django CustomMiddleware causing csrf_token issues during log in

I have been trying to implement this logic:
Whenever a user signs up, confirms his email, his account is active. However, in order to let the user gain full access to the website, he must enter some data first about his own self. I call it complete-profile.
I figured making a middleware is a good way to implement the logic. So I wrote the following:
class CompleteProfileMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
response = self.get_response(request)
if request.path == "/account/" + request.user.username + '/complete-registration/':
pass
elif request.user.is_anonymous:
pass
elif request.user.is_superuser:
pass
elif request.user.student.complete_profile:
pass
elif not request.user.student.complete_profile:
return redirect('/account/' + request.user.username + '/complete-registration/')
# Code to be executed for each request/response after
# the view is called.
return response
However, now, for accessing the complete profile page, people need to log in first. And during the log in process, it gives issues with the csrf token as: Forbidden. CSRF verification failed. Request aborted.
If I remove the middleware everything starts working again, so the issue has to be here.
Here's the login template:
<div class="main">
<section class="signup">
<div class="container">
<div class="row">
<div class="signup-content col-sm-12">
<form id="signup-form" class="signup-form" method="post" action="{% url 'login' %}">
{% csrf_token %}
<h2 class="form-title">Log In</h2>
{{ form | crispy}}
<input type="submit" style="margin-top: 10px" value="Login" class="button" id="" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
<div class="col-sm-12" style="text-align: right; margin-top: 5px">
Forgot Password?
</div>
<p class="loginhere">
New Here ? Create an account here
</p>
</div>
</div>
</div>
</section>
</div>
Without middleware everything works fine ?
You should send csrftoken during POST request, it's possible using django template language. You can use {% csrf_token %} template tag.

Testing login redirect

I am trying to write a test to see if my login redirects to the correct page. At the moment I am using this code which isn't working:
class TestAuth(TestCase):
def setUp(self):
self.client = Client()
#classmethod
def setUpTestData(cls):
user_login = get_user_model().objects.create(username='admin', email='admin#test.co.uk', password='asdf1234')
cls.user_login = user_login
def test_login_redirect(self):
response = self.client.post(
reverse('udt:login'),
{
'username': 'admin',
'password': 'asdf1234'
}
)
self.assertRedirects(response, reverse('udt:table_list'))
where udt:login equates to '/udt/accounts/login/' and udt:table_list equates to '/udt/table/'.
The login functionality is Django's built-in login with a custom template. When I run the test I get the following error:
AssertionError: 200 != 302 : Response didn't redirect as expected: Response code was 200 (expected 302)
However, when I actually test the login functionality in the app I get this:
[2017/05/30 14:43:22] HTTP POST /udt/accounts/login/ 302 [0.13, 127.0.0.1:60127]
[2017/05/30 14:43:22] HTTP GET /udt/table/ 200 [0.15, 127.0.0.1:60127]
which to me seems like it is in fact redirecting correctly.
So, my question is what is wrong with my test that is causing the assertion error? I am pretty new to testing in Django so it could just be something that I am missing, but it seems like the test should be passing to me.
Any help with this would be much appreciated.
UPDATE
The login template looks like this (just took the standard Django login template and added some bootstrap class names to it):
{% load bootstrap3 %}
<form id="login-form" method="post" action="{% url 'udt:login' %}">
{% csrf_token %}
<table class="table">
<tr>
<td><label for="id_username">Username</label></td>
<td><input id="id_username" name="username" type="text" class="form-control"></td>
</tr>
<tr>
<td><label for="id_password">Password</label></td>
<td><input id="id_password" name="password" type="password" class="form-control"></td>
</tr>
</table>
{% if form.errors %}
<p class=" label label-danger">
Your username and password didn't match.
Please try again.
</p>
{% endif %}
<input type="submit" value="Login" class="btn btn-primary pull-right" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
url for login looks like so:
url(r'^login/$', auth_views.login, {'template_name': 'auth/login.html'}, name='login')
I am using Django v.1.11.1.
You are creating the user incorrectly. You should use create_user instead of create(), so that the password is correctly hashed.
#classmethod
def setUpTestData(cls):
user_login = get_user_model().objects.create_user(username='admin', email='admin#test.co.uk', password='asdf1234')
As an aside, you can remove your setUp method as it is unnecessary. Django's TestCase class takes care of setting up self.client for you.
One more thing - your URL pattern is fine for Django 1.11, but you could update it to use LoginView to be compatible with Django 2.1+:
url(r'^login/$', auth_views.LoginView.as_view(template_name= 'auth/login.html'), name='login'),

Django: updating database row via table cell

Trying to create a Display in Django, which would look like this.
link: http://i47.tinypic.com/2lk2mw2.png
the number of fruits everyday is dynamic and different everyday.
the comment field is to be editable by the admin. the input would
then be used to update the row in the database
problem: so far I'm uncertain about how to go about allowing users to edit the comment column and present the changes in the database
**
fruits.html
**
{% for item in nodes %}
<tr>
<td class = "tablebord"><a href ="/nodes/node/{{ item.nodeid }}/">{{
item.nodeid }}</a></td>
<td class = "tablebord">{{ item.lastseen }} </td>
<td class = "tablebord"><div contenteditable>{{ item.comment }} <p>
<form action="" method="get">
<input type="text" name="q">
<input type="submit" value="test">
</form>
</p> </div> </td>
<td class = "tablebord">{{ item.lastipaddr }} </td>
</tr>
{% endfor %}
One solution that occurs to me:
In HTML:
Change method in form to POST.
Add CSRF Token to form.
Add hidden input with nodeid for parsing in view.
Pre-fill input with current comment.
<!-- Comment Cell -->
<td class = "tablebord">
<div contenteditable>
<form action="" method="post"> {% csrf_token %}
<input type="text" name="comment" value={{ item.comment }} />
<input type="hidden" value={{ item.nodeid }} name="nodeid" />
<input type="submit" value="edit" />
</form>
</div>
</td>
In views.py:
Import decorator for CSRF Token and Node model
Decorate view with CSRF Protect.
Check if form is submitted.
If so, get node and change comment.
Render template.
# decorator
from django.views.decorators.csrf import csrf_protect
from app.Node.models import Node
# view to handle table
#csrf_protect
def fruits(request):
nodes = Nodes.objects.all()
# user is posting: get edited node, change comment, and save
if request.POST:
nodeid = request.POST.get('nodeid')
edited_node = nodes.get(nodeid=nodeid)
edited_node.comment = request.POST.get('comment')
edited_node.save()
# render template with nodes
return render(request, 'fruits.html', {'nodes':nodes})
Hope this answers your problem.