I have created two different types of users - truck & company. Here is my registration page for a user
After registering, the data about whether the user is a truck or company will go to the database.
In my login page,
only Email and Password are to be entered. In my custom user creation form, I added the field username = email.
When I am trying to login with valid credentials, the page is not redirecting me to a particular page according to the user-type. Instead, an error which I created for invalid credentials in login.html is raising - "Your email and password didn't match. Please try again."
here's my code:
views.py:
def login_view(request):
title = "Login"
if request.method == 'POST':
form = LoginForm(data=request.POST)
email = request.POST.get('email', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=email, password=password)
if form.is_valid():
auth.login(request, user)
user_type = form.cleaned_data['Label']
if user.is_active & user_type == 'Truck':
return HttpResponseRedirect('/post_load/')
elif user_type == 'Company':
return HttpResponseRedirect('/live_deal/')
else:
form = LoginForm()
return render(request, 'registration/login.html', {'form' : form, 'title': title})
urls.py:
# url(r'^login/$', views.login_view),
# url(r'^accounts/login/$', views.login_view),
url(r'^login/$', 'django.contrib.auth.views.login', {'authentication_form': LoginForm}),
url(r'^accounts/login/$', 'django.contrib.auth.views.login', {'authentication_form': LoginForm}),
forms.py:
class LoginForm(auth.forms.AuthenticationForm):
email = forms.EmailField(label=_("Email"),widget=forms.EmailInput)
CHOICES= (('Truck', 'Truck'),('Company', 'Company'),)
Label = forms.ChoiceField(choices=CHOICES, label='Label', widget=forms.RadioSelect())
login.html:
{%extends "registration/header.html"%}
{% block content %}
{% if form.errors %}
<p>Your email and password didn't match. Please try again.</p>
{% endif %}
<form class="form-horizontal" method="post" action = "." >{%csrf_token%}
<div class="panel panel-default login">
<div class="panel-heading">
<span class="glyphicon glyphicon-lock"></span> Login</div>
<div class="panel-body">
<form class="form-horizontal" role="form">
<div class="form-group">
<div class='col-sm-6 col-sm-offset-4'>
<table border="0">
<div class="col-sm-4">
<tr><th><label for="id_user" class="col-sm-4 control-label">Email:</label></th><td>{{ form.email }}</td></tr> </div>
<div class="col-sm-4">
<tr><th><label for="id_password" class="col-sm-4 control-label">Password:</label></th><td>{{ form.password }}</td></tr> </div>
</table> </div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-8">
<div class="checkbox">
<label>
<input type="checkbox"/>
Remember me
</label>
</div>
</div>
</div>
<div class="form-group last">
<div class="col-sm-offset-4 col-sm-8">
<button type="submit" class="btn btn-success btn-sm">
Sign in</button>
<input type="hidden" name="next" value="/" />
<label class="col-sm-offset-3">
Forget Password?
</label>
</div>
</div>
</form>
</div>
<div class="panel-footer">
Not Registered? Register</div>
</div>
</form>
{% endblock %}
{% if form.errors %}
<p>Your email and password didn't match. Please try again.</p>
This error is rather broad. You could loop through it to see the actual errors.
Better yet; don't use your own authentication system just use Django's built-in system which also allows you to add extra fields to the user model.
Example:
from django.contrib.auth import authenticate, login
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
# Redirect to a success page.
else:
# Return a 'disabled account' error message
...
else:
# Return an 'invalid login' error message.
...
Note, you don't need to write your own login view, you can also use Django's login system to handle the form, pass reset/change, urls and templates (which you can override with your own template):
urls:
urlpatterns = [
url('^', include('django.contrib.auth.urls')),
]
Then /login/ will be your login page.
After it works with the Django contrib auth module, extend it with your own custom HTML login form.
django.contrib.auth.views
Related
I am new to Django Authentication system and I am unable to find the correct debugging method.
I want to create a function to handle login requests and I have done the necessary steps to do the same.
created a login url path in main project URLS.py file.
path('members/', include('django.contrib.auth.urls')),
path('members/', include('members.urls')),
created a login url in members app to point to a function created in views.py
urlpatterns = [
path('login/', views.login_user, name='login'),]
defined what to do when user comes to specific url
def login_user(request):
if request.method == 'POST':
print('-'*100)
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
messages.success(request, ("You are now logged in"))
return redirect('index')
else:
messages.success(request, ("Invalid credentials"))
return redirect('login')
return render(request, 'registration/Login.html')
I have created a Login Page in templates folder.
{% extends 'Base.html'%}
{% block title %}
Login to the Blog Page
{% endblock %}
{% block content%}
<h1>Members Login</h1>
<div class="form-group">
<form method="POST" action="">
{% csrf_token %}
<div class="mb-3">
<label for="exampleInputEmail1" class="form-label">User Name</label>
<input type="text" class="form-control" name = "username">
<div id="emailHelp" class="form-text">We'll never share your email with
anyone else.</div>
</div>
<div class="mb-3">
<label for="exampleInputPassword1" class="form-label">Password</label>
<input type="password" class="form-control" name="password">
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
<br>
</div>
{% endblock %}
Now when I get to the /members/login after submitting the user details the print statement in post method is not printed in the console. So I am suspecting that the post request is not being redirected to the login_user function. Can anyone help me out to identify why?
Djnago will fire the view that it first finds for the path members/login, and that is the login view of the django.contrib.auth module. You can swap the order of the views to visit the login view of your view:
urlpatterns = [
path('members/', include('members.urls')), # 🖘 `members.urls first
path('members/', include('django.contrib.auth.urls'))
]
But it might be better to give your view a different path, to prevent any confusion.
I have a class based view which shows a login-form.
The problem is that I can't display error messages. I am trying to send an error message in a parameter in the URL to display it inside the HTML template file. But it does not work.
Here is my code so far:
forms.py
# a class which act as a view - it displays the login-form
class LoginForm(AuthenticationForm, BaseLoginView):
username=forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))
password=forms.CharField(widget=forms.PasswordInput(attrs={'class':'form-control'}))
def get_context_data(self, **kwargs):
context = super(LoginForm, self).get_context_data(**kwargs)
context['error'] = ''
return context
urls.py
urlpatterns = [
path('login/', views_auth.LoginView.as_view(form_class=LoginForm, redirect_authenticated_user=True), name='login'), # login-page
]
views.py
# login functionality for the user
def custom_user_login(request):
if request.method == 'GET':
error_message = ''
return redirect('home')
elif request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
error_message = ''
# if the username & password is correct
user = authenticate(request, username=username, password=password)
if user is not None:
# Redirecting to the required login according to user type (admin / regular-user)
if user.is_superuser or user.is_staff:
login(request, user)
return redirect('admin_section/')
else:
login(request, user)
return redirect('/')
# display error message
else:
base_url = reverse('login') # /login/
query_string = urlencode({'error': 'The username & password combination are incorrect - please try again!'}) # error=The username & password combination are incorrect - please try again!
url = '{}?{}'.format(base_url, query_string) # /login/?error=The username & password combination are incorrect - please try again!
return redirect(url) # redirects to the login page with an error-message
login.html
<!-- error message -->
<div id="error" class="alert alert-danger alert-dismissible" role="alert">
×
{{ view.error }}
</div>
<form method="post" action="{% url 'custom_login' %}">
{% csrf_token %}
{% for field in form %}
<div class="form-group row">
{{ field.errors }}
<label for="{{ field.name }}" class="col-md-4 col-form-label text-md-right">{{ field.label }}</label>
<div class="col-md-6">
{{ field }}
</div>
</div>
{% endfor %}
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
Login
</button>
</div>
</form>
You don't need to manually collect, add to context, and display errors. The form itself stores the errors. You're already getting field-specific errors with your call to field.errors in the template, but you can also get non-field-specific errors with form.errors. See the Django docs on form errors for more details.
As an aside, you can display GET variables from the url in your templates. Simply use {{ request.GET.error }}. Again, there is no need to encode your error message in the url itself. It's not a good way to solve this problem, which Django has already solved for you.
I am not using django default admin dashboard and i am using my own custom template for the admin.but here i got some problem while editing and updating the user.I want to make email of every user unique in the database this code in my forms.py does pretty well while adding the user but while updating it i got some problem regarding the email.Since I have done the email unique in forms.py it is giving me error while updating also.How can i update users so that the edited user can have the same email but not same as the other user's email address.
forms.py
class RegisterForm(UserCreationForm):
def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(email=email).exists():
raise ValidationError('Email Already Exists')
return email
class Meta:
model = User
fields = ['username', "email", "password1", "password2",'is_superuser','is_staff','is_active']
views.py
def register(request):
if not request.user.is_superuser:
messages.warning(request, 'Permission Denied.You have no permission to register users.')
return redirect('students:home')
if request.method == "POST":
form = RegisterForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.save()
messages.success(request,'user created with username {}'.format(user.username))
return redirect('students:our_users')
else:
form =RegisterForm()
return render(request,'students/register.html',{'form':form})
def editusers(request,id):
if not request.user.is_superuser:
messages.warning(request, 'Permission Denied.You have no permission to perform this action.')
return redirect('students:our_users')
user = User.objects.get(id=id)
return render(request,'students/edit_users.html',{'user':user})
def updateusers(request,id):
if not request.user.is_superuser:
messages.warning(request, 'Permission Denied.You have no permission to perform this action.')
return redirect('students:our_users')
user = User.objects.get(id=id)
form = RegisterForm(request.POST,instance=user)
if form.is_valid():
user = form.save(commit=True)
user.save()
messages.success(request,'{} updated'.format(user.username))
return redirect('students:our_users')
else:
messages.error(request,'Error in Form')
return redirect('students:edit_user',user.id)
register template
<form action="" method="post">
{% csrf_token %}
{% bootstrap_form form %}
<div class="text-xs-right">
<button type="submit" class="btn btn-info">Add</button>
</div>
</form>
edituser template
<form action="{% url 'students:update_user' user.id %}" method="post">
{% csrf_token %}
<div class="form-group"><label for="id_username">Username</label><input type="text" name="username" maxlength="150" autofocus class="form-control" value="{{user.username}}" placeholder="Username" title="Required. 150 characters or fewer. Letters, digits and #/./+/-/_ only." required id="id_username">
<small class="form-text text-muted">Required. 150 characters or fewer. Letters, digits and #/./+/-/_ only.</small>
</div>
<div class="form-group"><label for="id_email">Email</label><input type="email" name="email" value="{{user.email}}" class="form-control" placeholder="Email" title="" required id="id_email"></div>
<div class="form-group"><label for="id_password1">Password</label><input type="password" name="password1" value="{{user.password}}" class="form-control" placeholder="Password" title="Your password must contain at least 8 characters.Your password can't be entirely numeric." required id="id_password1">
<small class="form-text text-muted"><ul><li>Your password must contain at least 8 characters.</li><li>Your password can't be entirely numeric.</li></ul></small>
</div>
<div class="form-group"><label for="id_password2">Password confirmation</label><input type="password" name="password2" value="{{user.password}}" class="form-control" placeholder="Password confirmation" title="Enter the same password as before, for verification." required id="id_password2">
<small class="form-text text-muted">Enter the same password as before, for verification.</small>
</div>
<div class="form-group"><div class="form-check"><input type="checkbox" name="is_superuser" {% if user.is_superuser %}checked="checked" {% endif %}
class="form-check-input" id="id_is_superuser"><label class="form-check-label" for="id_is_superuser" title="Designates that this user has all permissions without explicitly assigning them.">Admin status</label>
<small class="form-text text-muted">Designates that this user has all permissions without explicitly assigning them.</small>
</div></div>
<div class="form-group"><div class="form-check"><input type="checkbox" name="is_staff" {% if user.is_staff %}checked="checked" {% endif %} class="form-check-input" id="id_is_staff"><label class="form-check-label" for="id_is_staff" title="Designates whether the user can log into this admin site.">Staff status</label>
<small class="form-text text-muted">Designates whether the user can log into this admin site.</small>
</div></div>
<div class="form-group"><div class="form-check"><input type="checkbox" {% if user.is_active %}checked="checked" {% endif %} name="is_active" class="form-check-input" id="id_is_active"><label class="form-check-label" for="id_is_active" title="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.">Active</label>
<small class="form-text text-muted">Designates whether this user should be treated as active. Unselect this instead of deleting accounts.</small>
</div></div>
<div class="text-xs-right">
<button type="submit" class="btn btn-info">Update</button>
</div>
</form>
You can do it like this:
def clean_email(self):
email = self.cleaned_data['email']
if self.instance and self.instance.pk:
return email
else User.objects.filter(email=email).exists():
raise ValidationError('Email Already Exists')
return email
Here I am checking if form has any instance and if that instance has any primary key. This instance attribute is set in form when you pass it from view, for example in your code: form = RegisterForm(request.POST,instance=user).
I am trying to style errors using twitter bootstrap in my Django project. Right now, I have a simple form that asks for a person's email address, has them press a button, and then submits it to the database. It also has validation checking to see if the email is unique in the database. If it is not unique, it raises an error saying "This email is already registered". However, when the error is raised, for a duplicate email, it brings an ugly bullet point list next to the input field with the text This email is already registered. I'm trying to style it to where it has a little dialog show under the input text with a yellow i icon like it does when the input does not include an # sign, i.e. it isn't an email. The ugly bullet point also appears when a valid domain isn't included in the email, e.g. there isn't a .com appended.
I think the problem lies with the way my form html is set up, or how the view handles the form's errors. Maybe, because the form field is an EmailField, the is_valid indicator doesn't validate and therefore shows the twitter bootstrap alert.
How do I get it to show the alert every time? Below is my code:
form part of the index.html
<form class="form-inline" method="post">
<div class="input-group input-group-newsletter">
<div class="form-group">
{% csrf_token %}
{{ form }}
</div>
<div class="form-group">
<div class="input-group-append">
<button class="btn btn-secondary" type="submit">Button Text</button>
</div>
</div>
</div>
</form>
views.py
from django.shortcuts import render, HttpResponse
from django.views.generic import TemplateView
from appname.forms import AppForm
class AppView(TemplateView):
template_name = 'apps/index.html'
def get(self, request):
form = AppForm()
return render(request, self.template_name, {'form': form})
def post(self, request):
form = AppForm(request.POST)
if form.is_valid():
email = form.cleaned_data['email']
form.save()
form = AppForm()
args = {'form': form, 'email': email, 'signedup': True}
else:
args = {'form': form, 'signedup': False}
return render(request, self.template_name, args)
forms.py
from django import forms
from .models import AppModel
class AppForm(forms.ModelForm):
email = forms.EmailField(required=True,
label='',
widget=forms.EmailInput(attrs={'class': 'form-control',
'placeholder': 'Enter email...',
'name': 'email',
'aria-label': 'Enter email...',
'aria-describedby': 'basic-addon'}))
class Meta:
model = AppModel
fields = ('email',)
def clean_email(self, *args, **kwargs):
email = self.cleaned_data.get("email")
if AppModel.objects.filter(email__iexact=email).exists():
raise forms.ValidationError("This email is already registered.")
return email
You may want to try Django messages framework. This site shows how its done. I have tried it myself and works fine, though I haven't tried putting icons into it.
https://simpleisbetterthancomplex.com/tips/2016/09/06/django-tip-14-messages-framework.html
Update based on the comment below:
Here are the snippets in my project
in settings.py
from django.contrib.messages import constants as messages
...
MESSAGE_TAGS = {
messages.DEBUG: 'alert-info',
messages.INFO: 'alert-info',
messages.SUCCESS: 'alert-success',
messages.WARNING: 'alert-warning',
messages.ERROR: 'alert-danger',
}
messages.html template which can be included in any template where you want to have notifications
{% if messages %}
{% for message in messages %}
<div class="alert {{ message.tags }} alert-dismissible " role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
{{ message }}
</div>
{% endfor %}
{% endif %}
log-in.html template
<body>
{% include 'trip_monitor/messages.html' %}
<div class="login-form">
<form method="post">
{% csrf_token %}
<h2 class="text-center">Materials Management</h2>
<p align="center">Please <strong>log in</strong> to continue.</p>
<div class="form-group">
<input name="username" type="text" class="form-control" placeholder="Username" required="required" autofocus>
</div>
<div class="form-group">
<input name="password" type="password" class="form-control" placeholder="Password" required="required" id="password">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block">Log in</button>
</div>
</form>
</div>
</body>
views.py
from django.contrib import messages
def login(request):
if request.method == 'POST':
_username = request.POST['username']
_password = request.POST['password']
user = authenticate(request, username=_username, password=_password)
if user is not None:
auth_login(request, user)
return redirect('/trip/')
else:
messages.error(request, 'Username or Password is incorrect!') # this will be shown as pop-up message
return render(request, 'trip_monitor/login.html')
elif request.method == 'GET':
if request.user.is_authenticated:
return redirect('/trip/')
else:
return render(request, 'trip_monitor/login.html')
I want to create my own login page uses the e-mail address and password in django 1.7.
When complete box and I click "login" page back to the login page.
My view:
def get_user_by_email(email):
try:
return User.objects.get(email=email)
except User.DoesNotExist:
return None
def login_by_email(request):
email = request.POST.get('email')
password = request.POST.get('password')
username = get_user_by_email(email)
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active():
login(request, email)
return HttpResponseRedirect(reverse("myapp:dashboard"))
return render_to_response('myapp/login.html', context_instance=RequestContext(request))
My url:
url(r'^login/$', views.login_by_email, name='login'),
My template login.html
{% block content %}
<form class="form-horizontal" name="LoginForm" action="{% url 'myapp:login' %}" method="post">
{% csrf_token %}
<div class="control-group">
<label class="control-label" for="email">Email</label>
<div class="controls">
<input type="text" id="email" value="{{email}}" placeholder="Email">
</div>
</div>
<div class="control-group">
<label class="control-label" for="password">Password</label>
<div class="controls">
<input type="password" name="password" id="password" placeholder="Password">
</div>
</div>
<div class="control-group">
<div class="controls">
<button type="submit" class="btn">Login</button>
</div>
</div>
</form>
{% endblock %}
This line:
username = get_user_by_email(email)
Should be:
user_instance = get_user_by_email(email)
if user_instance:
username = user_instance.username
You are passing the user object to authenticate and it isn't able to log the user in.
Also, when you call the login function, you should pass the user as parameter:
login(request, user)
You are currently passing the email (django can't handle it this way)
Refer to the auth docs for more detail on how to handle custom login mechanisms
EDIT: Here's the complete view code
def get_user_by_email(email):
try:
return User.objects.get(email=email)
except User.DoesNotExist:
return None
def login_by_email(request):
email = request.POST.get('email')
password = request.POST.get('password')
user_instance = get_user_by_email(email)
if user_instance:
username = user_instance.username
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return HttpResponseRedirect(reverse("myapp:dashboard"))
return render_to_response('myapp/login.html', context_instance=RequestContext(request))