I have a django login form and when I click sign it, it is supposed to show some errors if something is wrong, however it doesn't appear in the html if I do print form.errors it appears in the console, here is an example : <ul class="errorlist"><li>username<ul class="errorlist"><li>User does not exist!</li></ul></li></ul> and then instantly after that it displays"POST /signin HTTP/1.1" in the console. I was wondering, why does it print the HTML in the console if I ask it to and not display it on screen. I tried {{form.errors}} and {{form.non_field_errors}}.
View Code:
def login_view(request):
form = LoginForm(request.POST or None)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username=username, password=password)
login(request, user)
return HttpResponseRedirect('/tickets/createticket')
stuff = {'form': LoginForm}
print form.errors
return render_to_response('tickets/login.html', stuff, context_instance=RequestContext(request))
Html:
{%load staticfiles %}
<link rel="stylesheet" type="text/css" href="{% static 'tickets/signin.css' %}"/>
<h1>Please Sign in</h1>
<form method="POST" id="signin">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Sign in" />
</form>
The error is here. You are passing form class:
stuff = {'form': LoginForm}
You should pass the form instance which you tried to validate:
stuff = {'form': form}
Related
I want to use ready Django LoginView, but in the same time I have to use my own view for registration in same HTML template. If in urls.py file I will connect 2 views than i will connect only first. So my question is that how can use LoginView in my own view and use 2 forms with jinja?
here is my views.py file and html ;)
def index(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
formlog = auth_views.LoginView.as_view(template_name='main/index.html')
if 'signup' in request.POST:
if form.is_valid():
form.supervalid()
form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Dear {username} you have been created a new accound!')
return redirect('main')
elif 'login' in request.POST:
if formlog.is_valid():
formlog.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You are now able to log in')
return redirect('main')
else:
form = UserRegisterForm()
formlog = auth_views.LoginView.as_view(template_name='main/index.html')
return render(request, 'main/index.html', {'form': form, 'formlog': formlog})
# this code is not working , but not returning any errors
HTML
{% if not user.is_authenticated %}
<!-- Login -->
<div class="container">
<div class="log-1">
<div class="log-0">
<p class="logtitle">BareTalk</p>
<form method="POST" name="login">
{% csrf_token %}
{{ formlog|crispy }}
<button class="log-button first" type="submit">Login</button>
</form>
<button class="log-button second"
onclick="modalwindowops.open();" id="signup">Sign Up</button>
</div>
</div>
</div>
<!-- Signup -->
<div class="modal-overlay">
<div class="modal-window">
<span class="close-modal" onclick="modalwindowops.close();">×</span>
<form method="POST" name="signup">
<p>Sign Up</p>
{% csrf_token %}
{{ form|crispy }}
<button type="submit">Sign Up</button>
</form>
</div>
</div>
{% else %}
<h1>Welcome back Amigo!</h1>
{% endif %}
Neither if 'signup' in request.POST: nor elif 'login' in request.POST: is triggered in your index() view because your HTML forms do not actually contain those inputs. Note that the name attribute is deprecated for the <form> element.
Instead you can add a hidden <input> inside your forms, like this:
<form method="POST">
{% csrf_token %}
{{ formlog|crispy }}
<input type="hidden" name="login" value="true" />
<button class="log-button first" type="submit">Login</button>
</form>
Also,
formlog = auth_views.LoginView.as_view(template_name='main/index.html')
saves a view to formlog, not a form, so calling formlog.is_valid() will cause an error.
Instead of
elif 'login' in request.POST:
if formlog.is_valid():
formlog.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You are now able to log in')
return redirect('main')
you probably will only need to do
elif 'login' in request.POST:
log_view = auth_views.LoginView.as_view(template_name='main/index.html')
log_view(request)
Calling is_valid(), save(), and doing the redirect is all done by LoginView already. If you want to still do the custom message.success() you will have to override one or more of the LoginView methods, but that is another topic.
Update:
You also need to change this line in the view: formlog = auth_views.LoginView.as_view(template_name='main/index.html') (before return render...) to:
formlog = AuthenticationForm(request)
Take this line outside of the else block.
Also add the import for the form at the top of your views.py:
from django.contrib.auth.forms import AuthenticationForm
This change is required because the template needs the form object (which is AuthenticationForm for LoginView by default) instead of the view object. The updated view function will look like:
from django.contrib.auth.forms import AuthenticationForm
def index(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if 'signup' in request.POST:
if form.is_valid():
form.supervalid()
form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Dear {username} you have been created a new accound!')
return redirect('main')
elif 'login' in request.POST:
log_view = auth_views.LoginView.as_view(template_name='main/index.html')
log_view(request)
else:
form = UserRegisterForm()
formlog = AuthenticationForm(request)
return render(request, 'main/index.html', {'form': form, 'formlog': formlog})
Note that this can be improved by providing feedback when the login credentials are invalid. As it is, this updated code only reloads a blank login form if the provided credentials don't work.
I am trying to show an error when the user enters wrong login credentials using form_template. So far I tried the below approach but it is not working.
Forms.py:
class UserForm(forms.Form):
username=forms.CharField(max_length=50)
password=forms.CharField(widget=forms.PasswordInput)
model=User
fields=['username', 'password']
Views.py:
class loginform(View):
template_name='essay/Login.html'
form_class=UserForm
def get(self,request): # if the request is get then only view the function
form=self.form_class(None)
return render(request, self.template_name, {'form': form})
def post(self,request):
form=self.form_class(request.POST)
if form.is_valid():
#user = form.save(commit=False) # it doesnot save in database, it is used to et clean the values
# clean data
username = form.cleaned_data['username']
password = form.cleaned_data['password']
# authenticate user:
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
if(request.user.is_prof==True):
return redirect('essay:file', )
else:
return redirect('essay:stdprofile')
else:
return render(request,self.template_name, {
'error_message': ' Login Failed! Enter the username and password correctly', })
else:
msg = 'Errors: %s' % form.errors.as_text()
return HttpResponse(msg, status=400)
return render(request, self.template_name, {'form': form})
Form_template:
{% for field in form %}
<div class="form-group">
<label class="control-label col-sm-2">{{ field.label_tag }}</label>
<div class="col-sm-10">{{ field }}</div> <!-- inputs on the rigth -->
</div>
{% endfor %}
Login.html:
<body>
<div class="login-card">
<h1>Log-in</h1><br>
<form class="form-horizontal" action="" method="POST" enctype="multiport/form-data">
{% csrf_token %}
{% include 'essay/form_template.html' %}
<input type="submit" name="login" class="login login-submit" value="login">
</form>
{% error_message %}
</div>
</body>
The problem I got when I enter invalid credentials, username and password fields vanish and it also does not display the error message.
In your field in form page add,
{{field.errors}}
or under csrf tag add,
{{form.errors}}
This will show all your field errors, for non field errors add,
{{form.non_field_errors}}
Also, you can also use Django builtin messages to display your custom message.
The error is because you are using {% error_message %}in your template, when the correct is {{ error_message }}.
Plus,
why not use Django messages?
You also can easily include message on Class Based Views - see here
I am working through the Tango With Django tutorial. I am trying to allow the user to register with the app. However, when the user presses the submit button, I get this error message:
Page not found (404)
Request Method: POST
Request URL: http://127.0.0.1:8000/rango/register/rango/register/
Using the URLconf defined in tango_with_django_project.urls, Django tried these URL patterns, in this order:
^admin/
^rango/ ^$ [name='index']
^rango/ ^about$ [name='about']
^rango/ ^add_category/$ [name='add_category']
^rango/ ^category/(?P<category_name_url>\w+)/$ [name='category']
^rango/ ^category/(?P<category_name_url>\w+)/add_page/$ [name='add_page']
^rango/ ^register/$ [name='register']
media/(?P<path>.*)
The current URL, rango/register/rango/register/, didn't match any of these.
I'm not sure how that weird path is being built. Here is registration template:
<!DOCTYPE html>
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>Register with Rango</h1>
{% if registered %}
Rango says: <strong>thank you for registering!</strong>
Return to the homepage.<br />
{% else %}
Rango says: <strong>register here!</strong><br />
<form id="user_form" method="post" action="rango/register/"
enctype="multipart/form-data">
{% csrf_token %}
{{ user_form.as_p }}
{{ profile_form.as_p }}
<input type="submit" name="submit" value="Register" />
</form>
{% endif %}
</body>
</html>
In order to get to the registration template, you need to click this link in the index template:
Register Here
Here is the register function in rango/views.py:
def register(request):
registered = False
if request.method == 'POST':
user_form = UserForm(data=request.POST)
profile_form = UserProfileForm(data=request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.save()
profile = profile_form.save(commit=False)
profile.user = user
if 'picture' in request.FILES:
profile.picture = request.FILES['picture']
profile.save()
registered = True
else:
print user_form.errors, profile_form.errors
else:
user_form = UserForm()
profile_form = UserProfileForm()
return render(request,
'rango/register.html',
{'user_form': user_form, 'profile_form': profile_form, 'registered': registered})
I am sure I am missing something small!
Currently you browser adds "rango/register/" to the end of the current URL.
If you changed it to "./" or "/rango/register/" it would point to itself, however these are not best practise.
For best practise use {% url "register" %} instead, that way it will automatically change is you change your url.py
e.g:
<form id="user_form" method="post" action="{% url "register" %}"
enctype="multipart/form-data">
Most likely the <form action> attribute is wrong.
Now it points relatively to:
rango/register/rango/register/
<form id="user_form" method="post" action="rango/register/" <--- relative
For a quick workaround try (not a best practice):
<form id="user_form" method="post" action="/rango/register/"
instead.
Learn how relative URL works within HTML pages and this should unravel the mystery.
It seems like the issue is with your URLs.py page - it seems like you haven't setup the url rewriting section of django
EDIT: the view now does log me in when I enter a correct username and password, but doesn't return any errors when I enter incorrect username and passwords.
I am using the generic login view provided by Django. This is my login.html template:
<body>
<h1>User Login</h1>
{% if form.has_errors %}
<p>Your username and password did not match.
Please try again.</p>
{% else %}
<form method="post" action=" . ">{% csrf_token %}
<p><label for="id_username">Username:</label>
{{ form.username }}</p>
<p><label for="id_password">Password:</label>
{{ form.password }}</p>
<input type="hidden" name="next" value="/" />
<input type="submit" value="login" />
</form>
{% endif %}
</body>
Now, I am following the tutorial in the book called "Pact Publishing. Learning Website Development with Django". The view never returns
form.has_errors
even though I purposely submit an incorrect username and password. It just keeps returning me to the same page after I click submit. Also, according to the HTML book I read, it said that the 'action' attribute in the form is the URL of the page on the server that will retrieve the information. Is that why it isn't working? Because my
action=" . "
?
EDIT: the view is the generic login view:
#sensitive_post_parameters()
#csrf_protect
#never_cache
def login(request, template_name='registration/login.html',
redirect_field_name=REDIRECT_FIELD_NAME,
authentication_form=AuthenticationForm,
current_app=None, extra_context=None):
"""
Displays the login form and handles the login action.
"""
redirect_to = request.REQUEST.get(redirect_field_name, '')
if request.method == "POST":
form = authentication_form(data=request.POST)
if form.is_valid():
# Ensure the user-originating redirection url is safe.
if not is_safe_url(url=redirect_to, host=request.get_host()):
redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)
# Okay, security check complete. Log the user in.
auth_login(request, form.get_user())
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
return HttpResponseRedirect(redirect_to)
else:
form = authentication_form(request)
request.session.set_test_cookie()
current_site = get_current_site(request)
context = {
'form': form,
redirect_field_name: redirect_to,
'site': current_site,
'site_name': current_site.name,
}
if extra_context is not None:
context.update(extra_context)
return TemplateResponse(request, template_name, context,
current_app=current_app)
and my urls.py is just
url(r'^$', main_page),
url(r'^user/(\w+)/$', user_page),
url(r'^login/$', login),
Ah, found the answer over here:
form.has_errors tag not working
form.has_errors
was replaced with
form.errors
Try this.
Login.Html
<form action ="." method = POST>
{% csrf_token %}
{{ form.as_p }}
<input type = "submit" value = "login" class="btn">
</form>
urls.py
from django.contrib.auth.views import login, logout
from django.conf.urls import *
urlpatterns = patterns('',
url(r'login/',login,kwargs = {'template_name' : 'templates/auth/login.html'},
url(r'logout', logout,kwargs = {'template_name' : 'templates/auth/logout.html'}),
)
settings.py
LOGIN_REDIRECT_URL = '/dashboard'
LOGIN_URL = '/login/'
I'm coding a login. When I programmed the form by hand I got it working.
The code below works:
views.py
def login_view(request):
if request.method == 'GET':
return render(request, 'app/login.htm')
if request.method == 'POST':
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=username, password=password)
if user is None:
return HttpResponseRedirect(reverse('error'))
if not user.is_active:
return HttpResponseRedirect(reverse('error'))
# Correct password, and the user is marked "active"
auth.login(request, user)
# Redirect to a success page.
return HttpResponseRedirect(reverse('home'))
template:
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<p><label for="id_username">Username:</label> <input id="id_username" type="text" name="username" maxlength="30" /></p>
<p><label for="id_password">Password:</label> <input type="password" name="password" id="id_password" /></p>
<input type="submit" value="Log in" />
<input type="hidden" name="next" value="" />
</form>
Great! But now I want to do the same thing using Django's forms.
The code below is not working because I get is_valid() == False, always.
views.py:
def login_view(request):
if request.method == 'POST':
form = AuthenticationForm(request.POST)
print form.is_valid(), form.errors, type(form.errors)
if form.is_valid():
## some code....
return HttpResponseRedirect(reverse('home'))
else:
return HttpResponseRedirect(reverse('error'))
else:
form = AuthenticationForm()
return render(request, 'app/login.htm', {'form':form})
template:
<form action="{% url 'login' %}" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
There are a bunch of people on stackoverflow complaining that they get is_valid always false. I have read all those posts, and as far as I can tell I'm not making any of those mistakes. I found a new mistake to make :-)
EDIT: I added a print in the code. The output when opening the login view and submitting is
[27/Dec/2013 14:01:35] "GET /app/login/ HTTP/1.1" 200 910
False <class 'django.forms.util.ErrorDict'>
[27/Dec/2013 14:01:38] "POST /app/login/ HTTP/1.1" 200 910
and so is_valid() is False, but form.errors is empty.
It turns out that Maxime was right after all (sorry) - you do need the data parameter:
form = AuthenticationForm(data=request.POST)
The reason for that, though, is that AuthenticationForm overwrites the signature of __init__ to expect the request as the first positional parameter. If you explicitly supply data as a kwarg, it will work.
(You should still leave out the else clause that redirects away on error, though: it's best practice to let the form re-render itself with errors in that case.)
Check out form.errors which will help you find out why.
If situation arises, that you don't have an option (I was trying to work with bootstrap modals and it was just not working), I had to do this, or else the modal would always trigger even if the form had not issues (and the is_valid is always False by default)
What I needed:
Show modal when I click a button
if errors, show on the same page, the modal, with the error.
In the modal template:
{% if not brand_form.is_valid and brand_form.errors %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script type="text/javascript">
$(window).on('load', (function() {
$('#brandAddModal').modal('show');
}));
</script>
{{ brand_form.non_field_errors }}
{% endif %}
In the view:
def add_brand_form(request):
form = BrandForm()
if request.method == 'POST':
form = BrandForm(data=request.POST)
if form.is_valid():
return HttpResponseRedirect('/home')
else:
return render(request, template_name='home.html', context={'brand_form':form})
return render(request, template_name='modal_add_brand.html', context={'brand_form':form})