I'm trying to display the login fields manually, instead of using:
{{form.as_p}}
I'm setting allauth as follows in order to login with email:
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_SIGNUP_PASSWORD_ENTER_TWICE = False
ACCOUNT_SESSION_REMEMBER = True
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_UNIQUE_EMAIL = True
In HTML I have the following:
<form class="login" method="POST" action="{% url 'account_login' %}">
{% csrf_token %}
<!-- Email input -->
<div class="form-outline mb-4">
{{form.email}}
<label class="form-label" for="form2Example1">Email address</label>
</div>
<!-- Password input -->
<div class="form-outline mb-4">
{{form.password}}
<label class="form-label" for="form2Example2">Password</label>
</div>
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<a class="button secondaryAction" href="{% url 'account_reset_password' %}">{% trans "Forgot Password?" %}</a>
<button class="btn btn-lg btn-block btn-primary" type="submit">{% trans "Sign In" %}</button>
</form>
The email field is not being displayed, I have also tried with:
{{form.user}}
and the field is not displayed
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 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
Although my User login is working perfectly fine but I am unable to handle User form validation on modal itself. I mean, I am able to get the user name and pwd and validate it but if the user name and pwd didn't match, the page is redirected to a Django template. But I want to show the message like username pwd didn't match on modal itself not on another Django template.
Modal code
<div class="modal signUpContent fade" id="ModalLogin" tabindex="-1" role="dialog">
<div class="modal-dialog ">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"> × </button>
<h3 class="modal-title-site text-center"> Login </h3>
</div>
<div class="modal-body">
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
{% if next %}
{% if user.is_authenticated %}
<p>Your account doesn't have 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 %}
<form action="{% url 'django.contrib.auth.views.login' %}" method="post">
{% csrf_token %}
{% if next %}
<input type="hidden" name="next" value="{{ next }}" />
{% endif %}
<div class="form-group login-username">
<div>
<input name="username" id="login-user" class="form-control input" size="20" placeholder="Enter Username" type="text" value="{{ username }}">
</div>
</div>
<div class="form-group login-password">
<div>
<input name="password" id="login-password" class="form-control input" size="20" placeholder="Password" type="password" value="">
</div>
</div>
<div class="form-group">
<div>
<div class="checkbox login-remember">
<label>
<input name="rememberme" value="forever" checked="checked" type="checkbox">
Remember Me
</label>
</div>
</div>
</div>
<div>
<div>
<input name="submit" class="btn btn-block btn-lg btn-primary" value="Log In" type="submit">
</div>
</div>
</form>
</div>
<div class="modal-footer">
<p class="text-center"> Not here before? <a data-toggle="modal" data-dismiss="modal" ng-href="#ModalSignup"> Sign Up. </a> <br>
<a data-toggle="modal" data-dismiss="modal" ng-href="#ModalPwdReset"> Lost your password? </a> </p>
</div>
</div>
</div>
setting.py
LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/index'
So, how to get error message on modal form itself ?
I have been having the same issue, I wanted to use the Django build in authentication system to make a login page for my portfolio/blog website, this means that I am not implementing custom forms/views at all for this, and I just create the view in the url.py directly from django.contrib.auth.views.login , I found a workaround that helps to my case, and maybe putting some logic in it others could find a way to adjust the idea to their projects as well, here is the code:
urls.py :
from django.conf.urls import url, include
from django.contrib import admin
from . import views as view
from django.contrib.auth import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^coltapp/', include('coltapp.urls')),
url(r'^$', view.HomePage.as_view(), name='home'),
url(r'accounts/login/$', views.login, name='login'),
url(r'accounts/logout/$', views.logout, name='logout', kwargs={'next_page': '/'}),
]
Notice this line:
url(r'accounts/login/$', views.login, name='login'),
Here I am using the build In Django login view - views.login - , so , like i said before, no custom form or views created for this pourpose.
Base.html
I am calling the modal as the bootstrap documentation recommend it, also, I am including this custom_modal.html inside of the base.html so i can use it in future operations; I have to point out that I have this on a nav-var, that's why is inside of a list item tag.
<li><a id="loginAnchor" data-toggle="modal" href="{% url 'login' %}" data-target="#custom_modal"><span class="glyphicon glyphicon-user"></span></a></li>
{# THIS WILL INCLUDE THE MODAL CONTACT WINDOW FOR FURTHER USE #}
{% include "coltapp/custom_modal.html" %}
custom_modal.html
a simple .html file with JUST the logic structure for the modal to work, but nothing else inside, no extended from base no nothing just as you can see.
<!-- Modal HTML -->
<div id="custom_modal" class="modal fade" >
<div class="modal-dialog">
<div class="modal-content modal-custom" >
</div>
</div>
</div>
In this way, i make this modal reusable, and after I will be able to inject any other data that I want inside of modal-content div by Ajax or whatever.
login.html
Here I managed the Rendering fields manually, I found this more practical as I have total control over each field from this form, remember, I have no view/form code for this login view, this comes with Django build-in auth views
<div id="login-jumbo" class="jumbotron">
<div style="margin-bottom:1%" class="modal-header">
<button id="login_close" type="button" class="close .login-close" data-dismiss="modal" aria-hidden="true">×</button>
<h1>Welcome back Nestor!</h1>
</div>
{% if form.errors %}
{% for error in form.non_field_errors %}
<div class="error-message">
<div class="alert alert-danger">
<h4>Ops! Invalid Data...</h4>
</div>
<ul><li><h5>{{ error|safe }}</h5></li></ul>
</div>
{% endfor %}
<script type="text/javascript">
var divisor = document.querySelectorAll(".form-div");
var len = divisor.length
for (let i=0; i < len; i++ ){
divisor[i].className += " has-error";
}
</script>
{% endif %}
<form id="login_form" action="{% url 'login' %}" method="POST">
{% csrf_token %}
{% for field in form.fields %}
{% if field == 'username' %}
<div class="form-group form-div">
<h4 class="control-label">{{ field|title }}</h4>
<input class="form-control" type="text" name="username">
</div>
{% else %}
<div class="form-group form-div">
<h4 class="control-label">{{ field|title }}</h4>
<input class="form-control" type="password" name="password">
</div>
{% endif %}
{% endfor %}
<div style="margin-top:2%" id="login_footer" align="right" class="modal-footer">
<button type="submit" class="btn btn-danger" value="login">Log In</button>
<input type="hidden" name="next" value="{{ next }}">
</div>
</form>
</div>
Have to note: I've managed the errors inside of this template,
{% if form.errors %} then I will call an alert message from bootstrap, this is really important for what I'm going to do in the next section in the JS file, also I've iterated over the fields and put them into a div in pairs, login, and password fields, and also I have made a little script that will add a class to those divs in case of errors found on form. class='has-error', these error classes comes directly from bootstrap for error handling.
- this is the data that will be rendered inside of the modal!
Jquery ajax request
The Ajax call is very self-explained, and also there are a lot of reference on internet about this o about how they have to be implemented
$(document).on('submit','#login_form', function(e){
e.preventDefault();
var login_form = $('#login_form');
var action = login_form.attr('action');
var method = login_form.attr('method');
var data_ = login_form.serialize();
$.ajax({
type: method,
url: action,
data: data_,
success: function(data, status) {
if ($(data).find('.alert-danger').length > 0) {
$('.modal-custom').html(data);
// console.log(data)
}else{
console.log('Log In Form Successfuly Summited')
$('#custom_modal').modal('hide')
location.reload(); //Reload the current document page on success
}
}
});
return false;
});
going through this, you pass the necessary data to the ajax call, and if this function is a success, you will apply some logic:
If find any element with ('.alert-danger') class on it, this means that the form has some errors on it, (you could use 'has-error' too), so if this condition is true, keep the modal open, and send the data again with the line:
$('.modal-custom').html(data);
'modal-custom' is the inner div from the custom_modal.html, where everything is rendered.
If not errors in form, that means no ('.alert-danger') class found on it, hide the modal, and reload the current document location, it means to reload the actual URL on the web browser, I made this because is a modal login page, sI i will need some elements to appear after the user is logged In.
also, I made to little more procs to clean the modal from errors on hiding, because if I was not logged In, and close the modal again without re-loading any page, these errors will appear again on the modal, so this was more for a cleanness procedure.
var restoreModalOnClose = function(){
var error_fields = $('.has-error')
var danger_pop = $('.alert-danger')
danger_pop.parent().remove()
$.each(error_fields, function(index, value){
$(value).removeClass('has-error');
// console.log(value)
})
};
$('#custom_modal').on('hidden.bs.modal', function (e){
console.log('here')
restoreModalOnClose()
});
I hope this helps to anyone in the future, I been reading a lot of post, docs and etc etc, and at the end, i found a workaround what satisfied what I was looking for.
JPG reference:
You can override the clean method:
from django.core.exceptions import ValidationError
class MyForm(forms.ModelForm):
.... # your code here
def clean(self):
if wrong_credentiels():
raise ValidationError("username pwd didn't match")
wrong_credentiels is a method where you can put in your verification logic
Is there way to create just one page for login and reset password?
I tried to create two forms page with following code in template:
<form action="" method="post" id="formLoginIndex">
{% csrf_token %}
<div id="elogin">
<p><label for="id_username">Login</label>
{{ form.username }}</p>
<p><label for="id_password">Пароль</label>
{{ form.password }}</p>
</div>
<p class="submit">
<button type="submit" class="enter">Enter</button>
{% if next %}
<input type="hidden" name="next" value="{{ next }}" />
{% else %}
<input type="hidden" name="next" value="/electricity/" />
{% endif %}
<button class="forgot" type="button" onclick="$('#forgotten').toggle('normal');">Forgot password?</button>
</p>
</form>
<div id="forgotten">
<form action="/reset/done/" method="post" id="formForgot">
{% csrf_token %}
<p>
<label for="id_username_forgot">Login</label>
<input id="id_username_forgot" type="text" name="username" maxlength="30" />
</p>
<p>
<label for="id_email">e-mail</label>
<input id="id_email" type="text" name="email" maxlength="40" />
</p>
<p class="submit">
<button class="remember" type="submit">Reset</button>
</p>
</form>
</div>
And urls :
url(r'^login/$', 'django.contrib.auth.views.login'),
url(r'^reset/done/$', 'django.contrib.auth.views.password_reset_done'),
However works only login feature. Reset doesn't work. Obviously is that I'm just doing smth wrong.
So should I load somehow views.password_reset into the same page or even rewrite django in auth views or there is another common solution?
The point is that you need a form to show the PasswordResetForm and it's action should be set to point to reset/
when this form is submitted via method POST, it's redirected to where the argument post_change_redirect points to, and there you can show the user that the password has been changed.
( In case the form evaluates to be correct , else, it would re-render the form with errors shown )
url(r'^reset/$', password_reset,
{'template_name':'your_template',
'post_change_redirect':'/reset/done/',
'extra_context':{'argument':'to tempate'}}, name='some_name'),
url(r'^reset/done/', password_reset_done,
{'template_name':'the template to show a success message',
'extra_context':{'message':'your password is changed successfully'}},),
looking at the defaults for this function ,It gives some cool info about how it works and its defaults if not given:
password_reset (request, is_admin_site=False,
template_name='registration/password_reset_form.html',
email_template_name='registration/password_reset_email.html',
subject_template_name='registration/password_reset_subject.txt',
password_reset_form=PasswordResetForm,
token_generator=default_token_generator,
post_reset_redirect=None,
from_email=None,
current_app=None,
extra_context=None)