What can cause MultiValueDictKeyError in Django? - 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?)

Related

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 csrf_token forbidden on reload

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>

django call function in all views (login)

I would like to call a function which is in /inscription/views.py since all views (because it's for the login). And I need to pass the username and the password in parameters to log the user.
def login_user(request):
if request.method =='POST':
auth_form=AuthenticationForm(data=request.POST)
if auth_form.is_valid():
username = request.POST.get('username')
password = request.POST.get('password')
uti = authenticate(username = username,password = password)
if uti:
if uti.is_active:
login(request, uti)
return HttpResponseRedirect('/accueil')
else:
return HttpResponse("Your account is disabled.")
else:
return HttpResponse("Invalid login details supplied.")
else:
auth_form=AuthenticationForm()
return render_to_response('authentication.html',
{'auth_form': auth_form}, RequestContext(request))
def logout_user(request):
logout(request)
And In my base.html I would like to add something like :
<label class="form_login">pseudo : </label>
<input type="text" name="username" id="id_username" class="login_input">
<label class="form_login">mot de passe : </label>
<input type="text" name="password" id="id_password" class="login_input">
<input value="login" type="submit"/>
<button>logout</button>
If I understand your question correctly, what you need is to force the user to login if he is not already logged in before he can access your views. To do this, all you need to do is to decorate your views with login_required decorator
from django.contrib.auth.decorators import login_required
#login_required
def my_view(request):
...
From the docs:
login_required() does the following:
- If the user isn’t logged in, redirect to settings.LOGIN_URL, passing
the current absolute path in the query string. Example:
/accounts/login/?next=/polls/3/.
- If the user is logged in, execute the view normally. The view code is
free to assume the user is logged in.
Update:
From your comment, now I understand that you need to make a form in all pages for the user to login, or a logout link if he is already logged in. First you need to define your URLs for these views:
url(r'^login/$', 'inscription.views.login', name='auth_login'),
url(r'^logout/$', 'inscription.views.logout', name='auth_logout'),
And in your base.html:
{% if user.is_authenticated %}
Logout
{% else %}
<form method="post" action="{% url 'auth_login' %}">
{% csrf_token %}
<input type="text" name="username" id="id_username">
<input type="text" name="password" id="id_password">
<input type="submit" value="Log in" />
</form>
{% endif %}
As a side note, I highly recommend you to use one of these reusable apps for auth and registration. unless you have strange requirements.
http://django-registration-redux.readthedocs.org/en/latest/
http://django-allauth.readthedocs.org/en/latest/
The problem which you are facing is , that u want the login and logout to work from other pages also, So, for this you need not to go for any extra function. All you need to do is, u just extend your base.html to all other html pages. Then you will surely be able to login and logout from all the pages.
Suppose you have login/logout in base.html
<label class="form_login">pseudo :</label>
<input type="text" name="username" id="id_username" class="login_input">
<label class="form_login">mot de passe : </label>
<input type="text" name="password" id="id_password" class="login_input">
<input value="login" type="submit"/>
<button>logout</button>
Now make some other html say test.html
There at the beginning you write
{% extends 'base.html' %}
followed by your HTML markup.
Don't forget to use
{% block content %} {% endblock %} **template tags**
In base as well as other HTML pages.
In other pages u try to write the complete code in template tags.
For query https://docs.djangoproject.com/en/1.7/topics/templates/
Also try using the concept of decorator.

django - middleware issue

I want to put a login form everywhere on my website, after following a few SO answers I decide to write my own middleware like this:
class LoginFormMiddleware(object):
'''
Put a login form in everypage of the website
'''
def process_request(self, request):
# if the top login form has been posted
if request.method == 'POST':
if 'logout_submit' in request.POST:
# log the user out
from django.contrib.auth import logout
logout(request)
form = LoginForm()
elif 'login_submit' in request.POST:
# validate the form
form = LoginForm(data=request.POST)
if form.is_valid():
# log the user in
from django.contrib.auth import login
login(request, form.get_user())
else:
form = LoginForm(request)
else:
form = LoginForm(request)
# attach the form to the request so it can be accessed
# within the templates
request.login_form = form
in my settings.py, I have:
import django.conf.global_settings as DEFAULT_SETTINGS
...
MIDDLEWARE_CLASSES = DEFAULT_SETTINGS.MIDDLEWARE_CLASSES + (
'base.mymiddleware.LoginFormMiddleware',
)
TEMPLATE_CONTEXT_PROCESSORS = DEFAULT_SETTINGS.TEMPLATE_CONTEXT_PROCESSORS + (
'django.core.context_processors.request',
)
The form, in base.html to be accesed from everywhere, looks like this:
{% if user.is_authenticated %}
<div class="login_box">
<form action="/myapp/logout/" method="post">{% csrf_token %}
<div class="col2"><a>{{ user.username }}</a></div>
<div class="col3"><input type="submit" value="Logout" name="logout_submit"/></div>
</form>
</div>
{% else %}
<form action="." method="post">
{% csrf_token %}
<div class="login_box">
<div class="error_box">
{% if request.login_form.errors %}
Incorrect User/Password
{% endif %}
</div>
<div class="col00"> <h4>{{ request.login_form.username.label_tag }}</h3></div>
<div class="col11">{{ request.login_form.username }}</div>
<div class="col22"><h4>{{ request.login_form.password.label_tag }}</h3></div>
<div class="col33">{{ request.login_form.password }}</div>
<div class="col44"><input type="submit" value="Login" name="login_submit"/></div>
<input type="hidden" name="next" value="{{ request.get_full_path }}" />
</div>
</form>
{% endif %}
Login works normally but, after doing it, each time I make a GET request user.is_authenticated seems to return false cause what I see is an empty LoginForm instead of the logout form.
I dont know if the problem is in my middleware (when request.method != 'POST' it returns form = LoginForm(request)) or it is something I am missing in my settings, or maybe using middleware for this was not a great idea...
I can't believe you have seen any SO answers that advocate putting this sort of logic in the middleware. (If you have, post the link so that I can downvote them.)
This really, really, really isn't the place to do this sort of thing. Write a specific view and set the action parameter of the login form to that view.
However, I suspect your underlying issue is that you're not using RequestContext to render the other views, so the user object is not passed to the template.
Your implementation doesn't make much sense. A login form with action attribute is "." is wrong and will lead to conflicts.
You should have a login view, not a login middleware. The action attribute of the login form should be the reversed url of your login view.
In your login form, you should specify a next hidden input for example:
<input name="next" type="hidden" value="{{ request.POST.next|default:request.path }}" />
Following that, it can be in your base template or anywhere in the website.
This is also valid for logout.