I'm using Django 3.0.2 + Boostrap. I have created a registration/login.html page. The contents of this page are shown below.
The page renders correctly and most of it works OK. However, I am unable to login to my website through this page. I keep getting Your username and password did not match. Please try again. I can login to the admin website without any issues if I use the same username/password. I am not sure what is wrong with my login.html. Any ideas?
{% extends "base.html" %}
{% block content %}
{% if form.errors %}
<p>Your username and password did not match. Please try again.</p>
{% endif %}
{% if next %}
{% if user.is_authenticated %}
<p>Your account does nohave access to this page. To proceed,please login with an account that has access.</p>
{% else %}
<p>Please login to see this page.</p>
{% endif %}
{% endif %}
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-lg-6">
<div class="p-5">
<div class="text-center">
<h1 class="h4 text-gray-900 mb-4">Welcome Back!</h1>
</div>
<form class="user" method="post" action="{% url 'login' %}">
{% csrf_token %}
<div class="form-group">
<input type="text" class="form-control form-control-user" id="exampleInputUserName" placeholder="Username">
</div>
<div class="form-group">
<input type="password" class="form-control form-control-user" id="exampleInputPassword" placeholder="Password">
</div>
<input type="submit" class="btn btn-primary btn-user btn-block" value="Login">
<input type="hidden" name="next" value="{{ next }}">
</form>
<hr>
<div class="text-center">
<a class="small" href="forgot-password.html">Forgot Password?</a>
</div>
<div class="text-center">
<a class="small" href="register.html">Create an Account!</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
Contents of views.py:
from django.contrib.auth import logout
def logout_view(request):
"""Log out user from the website."""
logout(request)
Your input types are missing the name attribute. As per the Mozilla docs:
A string specifying a name for the input control. This name is
submitted along with the control's value when the form data is
submitted.
So the name is submitted with the form. But what if there is no name attribute?
Same Documentation explains:
Consider the name a required attribute (even though it's not). If an
input has no name specified, or name is empty, the input's value is
not submitted with the form.
So your username and password are not sent to the backend.
You need to provide the name attributes to your input types.
<form class="user" method="post" action="{% url 'login' %}">
{% csrf_token %}
<div class="form-group">
<input type="text" class="form-control form-control-user" id="exampleInputUserName" placeholder="Username" `name="username"`>
</div>
<div class="form-group">
<input type="password" class="form-control form-control-user" id="exampleInputPassword" placeholder="Password" name="password">
</div>
<input type="submit" class="btn btn-primary btn-user btn-block" value="Login">
<input type="hidden" name="next" value="{{ next }}">
</form>
It is front-end issue, not particularly related to Django.
I'm currently trying to override a Django allauth template. So far, I followed all the recommendations on similar questions to mine:
overriding default templates of django-allauth
How to override template in django-allauth?
However, my goal is just change the default Django allauth without making new views or forms. (In previous projects I used to override the default forms constructor classes with the helper of Django Crispy Forms which is not possible in this particular case.)
I believe there is a way to ignore the {{form}} variable and just define a working form from scratch. Currently, I have my template being successfully being displayed when I navigate to 'account_login'. However, when I press Sign In nothing happens.
Here is my myapp/templates/account/login.html file:
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}
Sign In to {{ SITE_NAME }}
{% endblock %}
{% block body %}
<div class="centered">
<img class="logo" src={% static 'imgs/logo.png' %} alt="" width="100" height="100">
<form id="login_form" class="form-signin" method="post" action="{% url 'account_login'%}">
{% csrf_token %}
<label for="inputLogin" class="sr-only">Email address or Username</label>
<input type="text" id="login" class="form-control" placeholder="Email or Username" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" id="password" class="form-control" placeholder="Password" required>
<div class="note mb-3">
<label>
<input type="checkbox" value="remember" id="remember"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<div class="note mb-3 text-center">
<p>Forgot? Retrieve your login.</p>
<p>Not registered? <a href={% url 'account_signup'%}>Sign Up!</a></p>
</div>
</form>
</div>
{% endblock %}
Yes, you can customize it the way you want. It is rather simple.
When you use {{ form.as_p }} the page renders the form. And if you inspect the form you will notice that the page rendered the following form:
notice the id="" and the name="" you have to name it the exact same.
With that your code should look like this:
<form id="login_form" class="form-signin" method="post" action="{% url 'account_login'%}">
{% csrf_token %}
<label for="inputLogin" class="sr-only">Email address or Username</label>
<input type="text" name="login" id="id_login" class="form-control" placeholder="Email or Username" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" name="password" id="id_password" class="form-control" placeholder="Password" required>
<div class="note mb-3">
<label>
<input type="checkbox" name="remember" value="remember" id="id_remember"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<div class="note mb-3 text-center">
<p>Forgot? Retrieve your login.</p>
<p>Not registered? <a href={% url 'account_signup'%}>Sign Up!</a></p>
</div>
</form>
And you should be good to go.
So, I've been racking my brain on this for 2 days now. Any help would be awesome!
At the heart of my issue, I believe, is that I have nested modals and a custom bootstrap form in both: the first for login, and the second for signup. Let's assume in one case I want to do all my validations server-side, and possibly get full control over each of the error validation messages, as well as how and where they should appear respective to their input. How do I do that using django.contrib.messages?
** If I could use some of Bootstrap 4's built-in methods for validation as a first line of defense, or data-validate-on-blur to work like how it does with Zurb Foundation's Abide, even better.
Template tags in each base.html modal:
{% if messages %}
<div class='container-fluid bg-white mt-5 pt-5 pl-4 mb-4'>
{% for message in messages %}
<p class="small font-poller text-danger">{{ message }}</p>
{% endfor %}
</div>
{% endif %}
Trials and tribulations thus far:
As it stands, and with the various work-arounds I've found on Stack Overflow, i.e. using jQuery to toggle the modal (not the prettiest as it reloads the page), the best I've been able to do still bleeds my messages in between modals and/or my redirect views.
I've read threads on how to clear Django messages, and thought that might be a fix, so if after I close a modal or open a new modal, the messages essentially are cleared out until the form is submitted once again. In other words, the login error messages are unique to the login modal when its form's submit button is pressed, and signup error messages are unique to the signup modal when its form's submit button is pressed.
Unfortunately, I haven't figured out how to use a view (views.py), to successfully achieve this. The thought comes to mind that since because I'm using modals to trigger that event, I would have to use jQuery for that, but I have failed on that front also. I'm really hoping there is a more straight-forward solution to this.
Thanks in advance,
Dev
PS - my snippets:
views.py
def signup(request):
signup_errors = User.objects.validation(request.POST, 'register')
if len(signup_errors):
for error in signup_errors.values():
messages.error(request, error)
return redirect('/')
else:
new_user = User.objects.create(
first_name = request.POST['first_name'],
last_name = request.POST['last_name'],
dob = request.POST['dob'],
phone = request.POST['phone'],
address = request.POST['address'],
city = request.POST['city'],
state = request.POST['state'],
zipcode = request.POST['zipcode'],
email = request.POST['email'],
password =
bcrypt.hashpw(request.POST['password'].encode(), bcrypt.gensalt()))
request.session['first_name'] = new_user.first_name
request.session['id'] = new_user.id
messages.info(request, 'You have successfully submitted your
information.')
return redirect('/menu')
def login(request):
login_errors = User.objects.validation(request.POST, 'login')
if len(login_errors):
for error in login_errors.values():
messages.error(request, error)
return redirect('/')
else:
current_user = User.objects.get(email=request.POST['email'])
request.session['first_name'] = current_user.first_name
request.session['id'] = current_user.id
messages.info(request, 'You have successfully logged in.')
return redirect('/menu')
models.py
class UserManager(models.Manager):
def validation(self, postData, error_validation):
errors = {}
if error_validation == 'register':
if not NAME_REGEX.match(postData['first_name']):
errors['first_name'] = "First name can only contain
letters!"
if len(postData['last_name']) < 1:
errors['last_name'] = "Last name cannot be blank."
if not NAME_REGEX.match(postData['last_name']):
errors['last_name'] = "Last name can only contain letters!"
if error_validation == 'login':
user = User.objects.filter(email=postData['email'])
if not user:
errors['user_login'] = "No account with that email in
our system."
elif not bcrypt.checkpw(postData['password'].encode(),
user[0].password.encode()):
errors['password_login'] = "Invalid email and/or
password!"
return errors
login modal in base.html
<div class="modal fade text-dark" id="loginModal">
<div class="modal-dialog">
<div class="modal-content font-paytone">
<div class="modal-header shadow p-3 bg_primary rounded">
<h5 class="modal-title font-poller text-light text_shadow_success2" id="loginModal">Login <i class="fa fa-user text-center ml-1"></i></h5>
<button class="close" data-dismiss="modal"><span>×</span></button>
</div>
<div class="modal-body">
<form id="login-form" action="{% url 'ecommerce_app:login' %}" method="POST" novalidate>
{% csrf_token %}
<div class="form-group">
<input type="email" name="email" class="form-control form-control-lg" placeholder="Email" required>
</div>
<div class="form-group">
<input type="password" name="password" class="form-control form-control-lg" placeholder="Password" required>
</div>
<input id="login-form-submit-btn" type="submit" class="btn btn-success btn-block border bg_primary btn_login" value="Log In">
</form>
<p class="pt-2 font-passion">Don't have an account? Sign up below!</p>
<button id="login-form-signup-btn" class="btn btn-info btn-block border" data-toggle="modal" data-target="#registerModal">Sign Up</button>
</div>
{% if messages %}
<div class="modal-footer">
<div class='container-fluid bg-white'>
{% for message in messages %}
<p class="small font-poller text-danger">{{ message }}</p>
{% endfor %}
</div>
</div>
{% endif %}
</div>
</div>
</div>
register modal in base.html
<div class="modal fade text-dark" id="registerModal">
<div class="modal-dialog">
<div class="modal-content font-paytone">
<div class="modal-header shadow p-3 bg_primary rounded">
<h5 class="modal-title font-poller text-light text_shadow_info" id="registerModal">Sign Me Up! <i class="fa fa-user-plus ml-1"></i></h5>
<button class="close" data-dismiss="modal"><span>×</span></button>
</div>
<div class="modal-body">
<form id='signup-form' action="/signup/" method="POST" novalidate>
{% csrf_token %}
<div class="form-row">
<div class="form-group col-md-6">
<label for="first_name">First Name</label>
<input type="text" name="first_name" class="form-control" required>
</div>
<div class="form-group col-md-6">
<label for="last_name">Last Name</label>
<input type="text" name="last_name" class="form-control" required>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label for="dob">Date of Birth</label>
<input type="date" name="dob" class="form-control" required>
</div>
<div class="form-group col-md-6">
<label for="phone">Phone #</label>
<input type="tel" name="phone" class="form-control" required>
</div>
</div>
<div class="form-group">
<label for="address">Address</label>
<input type="text" name="address" class="form-control" placeholder="Street" required>
</div>
<div class="form-group">
<div class="form-row">
<div class="col-7">
<input type="text" class="form-control" name="city" placeholder="City" required>
</div>
<div class="col">
<input type="text" class="form-control" name="state" placeholder="State" required>
</div>
<div class="col">
<input type="text" pattern="[0-9]{5}" name="zipcode" class="form-control" placeholder="Zip" required>
</div>
</div>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" name="email" class="form-control" required>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<!-- <label for="password">Password</label> -->
<input type="password" name="password" class="form-control" placeholder="Password" required>
</div>
<div class="form-group col-md-6">
<!-- <label for="confirm">Confirm Password</label> -->
<input type="password" name="confirm" class="form-control" placeholder="Confirm Password" required>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-info btn-block font-fredoka">Register</button>
{% if messages %}
<div class='container-fluid bg-white mt-5 pt-5 pl-4 mb-4'>
{% for message in messages %}
<p class="small font-poller text-danger">{{ message }}</p>
{% endfor %}
</div>
{% endif %}
</div>
</form>
</div>
</div>
</div>
PSS - if I can help to clarify anything else please let me know
Well, I think I solved my own problem and am somehow compelled to share with others the solution as I think I actually lost sleep over this one. Anyway, I'm not really sure if this is what Django message class 'extra_tags' attribute was originally intended for, but for all intents and purposes it is a clean fix and allows me control over both server-side and client validation messages.
First, I assign extra_tags to 'register' and 'login' respectively when I create and append each message instance:
views.py
def signup(request):
errors = User.objects.validation(request.POST, 'register')
if len(errors):
for error in errors.values():
messages.add_message(request, messages.ERROR, error, extra_tags="register")
return redirect('/')
def login(request):
errors = User.objects.validation(request.POST, 'login')
if len(errors):
for error in errors.values():
messages.add_message(request, messages.ERROR, error, extra_tags="login")
return redirect('/')
I check to see if there are messages, then iterate through them, checking if the tag is 'register' (or 'login'), and if so, render some text, if not, don't render anything.
base.html
{% if messages %}
{% for message in messages %}
{% if 'register' in message.tags %}
<p class="small font-poller text-danger registration_error_message">{{ message }}</p>
{% endif %}
{% endfor %}
{% endif %}
Last but not least, after you submit the form through either modal, you will need to reload the modal with the aforementioned error (or success) messages. To have each modal show its respective messages you will have to differentiate and then toggle to open each one the same way I did using template_tags in the base.html, only this time using a little jQuery:
<script>
$(document).ready(function() {
{% if messages %}
{% for message in messages %}
{% if 'login' in message.tags %}
$('#loginModal').modal('toggle');
{% elif 'register' in message.tags %}
$('#registerModal').modal('toggle');
{% endif %}
{% endfor %}
{% endif %}
});
</script>
I have a custom page which calls allauth signup view (custom_passcheck.html)
<form action="{% url 'account_signup' %}" method="post" class="form">
{% csrf_token %}
<BR>
<BR>
<BR>
<center>
<div class=signuponepage>
<div class=sign-up>
<div class=signup-box>
<div class="form-element email-address">
<label id="email-address-label">
<strong>
Create a password (it must be 6 characters long)
</strong>
<input type="hidden" name="username" value="{{ pemail }}">
<input type="hidden" name="email" value="{{ email }}">
<input type="text" maxlength="19" name="password1" value="" placeholder="Password">
<input type="text" maxlength="19" name="password2" value="" placeholder="Password (again)">
</label>
</div>
<div class="form-element nextstep-button">
{% buttons %}
<button type="submit" class="btn btn-primary btn-sm">
Finish {% bootstrap_icon "chevron-right" %}
</button>
{% endbuttons %}
</div>
</div>
</div>
</div>
</center>
</form>
Now, if a user puts in password less than 6 chars, it will raise an error and redirect the user to allauth signup page (/account/signup)
Question: instead of redirecting to (/account/signup), how can i redirect to the custom page (custom_passcheck.html) while preserving POST data
Here's my HTML code:
{% extends "base.html" %}
{% block content %}
<form class="form-horizontal" action="/application/" method="get">
<div class="control-group">
<label class="control-label" for="userid">User ID</label>
<div class="controls">
<input type="text" id="userid" placeholder="Email">
</div>
</div>
<div class="control-group">
<label class="control-label" for="pass">Password</label>
<div class="controls">
<input type="password" id="pass" placeholder="Password">
</div>
</div>
<div class="control-group">
<div class="controls">
<input type="submit" class="btn" value="Sign in">
<br>
Forgot password?
<br>
Change password?
</div>
</div>
</form>
{% endblock %}
Here's my function in my view:
def application(request):
print request.GET
message=[]
for key,value in request.GET:
message.append("%s:%s"%key,value)
return HttpResponse(message)
Here no matter what I input, my 'print request.GET' prints a <QueryDict: {}>.
I can't figure out how to debug this. Any clue?
none of your inputs have name attributes,
name attributes are what are used to populate data for GET request.
<input type="password" id="pass" name="pass" placeholder="Password">
The above will show up with key name in request.GET
You're returning the last message, I suppose you want to render the template instead?
Try render_to_response instead.