login based on user roles - django

problem with my assignment....
I also need to make users login based on whether their role (usertype) is 'reader' or 'client' to be redirected to the proper welcome page. Plus i want to use my custom model (User's username & password) for login credentials. I have read the django docs custom auth but i still don't know i will implement it into my project.
models.py
class User(models.Model):
id = models.AutoField(primary_key=True, unique=True)
title = models.CharField(max_length='10')
surname = models.CharField(max_length='50')
firstname = models.CharField(max_length='50')
username = models.CharField(max_length='50', unique=True)
password = models.CharField(max_length='50')
email = models.EmailField(max_length='50')
phone = models.BigIntegerField(max_length='12')
city = models.CharField(max_length='50')
country = models.CharField(max_length='50')
usertype = models.CharField(max_length=13)
views.py
def login(request):
c = {}
c.update(csrf(request))
return render_to_response('login.html', c)
def auth_view(request):
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request, user)
return HttpResponseRedirect('adminwelcome')
else:
return HttpResponseRedirect('invalid')
template
{% extends "main.html" %}
{% block title %}Log In - {{ block.super }}{% endblock %}
{% block content %}
{% if form.errors %}
<p>Sorry, that is not a valid username or password</p>
{% endif %}
<form action = "auth_view" method="post"> {% csrf_token %}
<label for="username">Username:</label>
<input type="text" name="username" value="" id="username" />
<br />
<label for="password">Password:</label>
<input type="password" name="password" value="" id="password" />
<br />
<input type="submit" value="Login" />
</form>
<p>Not Registered? Create Account </p>
{% endblock %}

What i did was that when my User model form is being saved, it should get the username, password and email and create a user in the Django auth User table using this line of code
User.objects._create_user(request.POST['username'], request.POST['email'], request.POST['password'],False,False)
This is the full code in the views.py
def register(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
User.objects._create_user(request.POST['username'], request.POST['email'], request.POST['password'],False,False)
# Redirect to the document list after POST
return HttpResponseRedirect('register_success')
else:
form = RegisterForm()
args = {}
args.update(csrf(request))
args['forms'] = RegisterForm()
return render_to_response('register.html', args)
Then for the login based on roles, I had to make the user a staff from the admin end by setting the 'is_staff' = true. After that, all i had to do was pass the 'is_staff==True' in the auth_view request during login authentication. A bit dirty but it does the trick. Any further optimization is appreciated. Cheers.
Views.py
def auth_view(request):
username1 = request.POST.get('username', '')
password1 = request.POST.get('password', '')
user = auth.authenticate(username=username1, password=password1)
#check if user has been set to staff (reader), redirect to reader welcome
if user is not None and user.is_staff==True:
auth.login(request, user)
return HttpResponseRedirect('readerwelcome')
#check if user is not staff(client), redirect to client welcome
elif user is not None:
auth.login(request, user)
return HttpResponseRedirect('clientwelcome')
#if login details not found, return error page
else:
return HttpResponseRedirect('invalid')

Related

Django : How i can logged in by email instead of username

I want to make the email be set in the frontend of the django application.
I have go and create this class to make the authentification based on the email
class EmailBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
UserModel = get_user_model()
try:
user = UserModel.objects.get(email=username)
except UserModel.DoesNotExist:
return None
else:
if user.check_password(password):
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
Then I have go and define the path of this class in the settings.py
Everything is good without error and I logged in by typing the email. But in the frontend, the label is still "Username". How can I modify it?
Here it's the Html code form login page:
<form method="POST">
{% csrf_token %} <!--this protect our form against certeain attacks ,added security django rquires-->
<fieldset class="form-group">
{{ form|crispy}}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Login</button>
<small class="test-muted ml-2">
<a class="ml-2" href="{% url 'password_reset' %}">Forgot Password?</a>
</small>
</div>
<!--- put div for a link if he is already have account--->
<div class="border-top pt-3">
<small class="test-muted">Need an account? <a class="ml-2" href="{% url 'register' %}">Sign Up</a></small>
<!--it a bootstrap -->
</div>
</form>
Edited:
This is the view code:
def login_view(request):
context = {}
user = request.user
destination = get_redirect_if_exists(request)
if request.method == "POST":
form = LoginForm(request.POST)
if form.is_valid():
email = form.cleaned_data["email"]
password = form.cleaned_data["password"]
user = authenticate(request, email=email, password=password)
if user == None:
attempt = request.session.get("attempt") or 0
request.session['attempt'] = attempt + 1
return render(request, 'pages/login.html')
else:
login(request, user)
destination = get_redirect_if_exists(request)
if destination:
return redirect(destination)
return redirect("home")
return render(request, 'pages/login.html')
and this is the login form code:
class LoginForm(UserCreationForm):
email = forms.CharField(label='email')
password = forms.CharField(label='password')
Probably you should change form
urlpatterns = [
path('login/', LoginView.as_view(authentication_form=YourForm), name='login'),
]
class YourForm(AuthenticationForm):
username = forms.CharField(widget=TextInput(attrs={'class':'validate','placeholder': 'Username or Email'}))
password = forms.CharField(widget=PasswordInput(attrs={'placeholder':'Password'})

Django Edit Profile View not saving new email value

I am (attempting to) implement the ability for a user to edit and update their email address on their profile page. I am getting no errors when doing this end to end but the new email is not being saved to the DB.
Everything seems to be working, even the redirect to the profile page in the edit_profile function, but the save() doesn't seem to be working, the users email doesn't update and when I am redirected back to the profile page, the email is still the current value.
Thanks!
Model:
class CustomUser(AbstractUser):
email = models.EmailField(_('email address'), unique=True)
is_pro = models.BooleanField(default=False)
is_golfer = models.BooleanField(default=False)
def __str__(self):
return self.email
Form
class EditProfileForm(forms.Form):
email = forms.EmailField(
label='', widget=forms.TextInput(attrs={'class': 'form-field'}))
View
#login_required
def edit_profile(request):
if request.method == "POST":
form = EditProfileForm(request.POST)
if form.is_valid():
email = form.cleaned_data["email"]
user = CustomUser.objects.get(id=request.user.id)
user.save()
return redirect("typeA", username=user.username)
else:
form = EditProfileForm()
return render(request, "registration/edit_profile.html", {'form': form})
URLS
urlpatterns = [
path('type_a_signup/', ASignUpView.as_view(), name='a_signup'),
path('type_b_signup/', BSignUpView.as_view(), name='b_signup'),
path('login/', LoginView.as_view(), name='login'),
path('password_reset', PasswordResetView.as_view(), name='password_reset'),
path('typea/<username>/', typeA, name='typeA'),
path('typeb/<username>/', typeB, name='typeB'),
path('login_success/', login_success, name='login_success'),
path('edit_profile/', edit_profile, name='edit_profile'),
]
Template
<div class="container">
<div class="form-container">
<h2>Edit profile</h2>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div>
{{ form.email.label_tag }}
<input type="text" class="form-control {% if form.email.errors %}is-invalid{% endif %}" id="id_email"
name="email" value='{{ form.email.value|default:user.email }}'>
{% if form.email.errors %}
<div>{{ form.email.errors }}</div>
{% endif %}
</div>
<button type="submit">Submit</button>
</form>
<br>
</div>
You never set the email field of the object. You should set this with:
#login_required
def edit_profile(request):
if request.method == "POST":
form = EditProfileForm(request.POST)
if form.is_valid():
email = form.cleaned_data["email"]
user = request.user
user.email = email # 🖘 set the email field
user.save()
return redirect("typeA", username=user.username)
else:
form = EditProfileForm()
return render(request, "registration/edit_profile.html", {'form': form})
You should only redirect in case the form is successful. If it is not, Django will rerender the form with the errors.

ValueError : The given username should be set

I am trying to write my method to add a User type object on registration. Here is the code:
views.py
def registration(request):
c= {}
c.update(csrf(request))
state = "Please Register below..."
username = None
email = None
password = None
user_success = None
user_created = None
if request.POST:
username = request.POST.get('username')
email = request.POST.get('email')
password = request.POST.get('password')
print "username ",username
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
user_created = True
else:
user_created = False
else:
user = User.objects.create_user(username=username,password=password,email=email)
user.save()
user.is_active = True
user_success = True
return render_to_response('register.html',{'success':user_success,'created':user_created,'username': username},context_instance = RequestContext(request))
forms.py
class RegistrationForm(forms.Form):
username = forms.CharField()
email = forms.EmailField()
password = forms.CharField()
templates/register.html is:
{% extends "base.html" %}
{% block pageContent %}
<div class="container">
<form action="/register" method="post">
{% csrf_token %}
username:
<input type="text" name="username" value="{{ username}}" /><br />
password:
<input type="password" name="password" value="" /><br />
Email:
<input type="text" name="email" value="{{email}}" /><br />
<input type = 'submit' value='Register' />
</form>
</div>
{% endblock %}
Can anyone please help me spot the error? Also let me know if I am doing the registration right
The value of username at this point must evaluate to True.
user = User.objects.create_user(username=username,password=password,email=email)
# ^^^^^^^^ this can't be a bool() false
Why? That error message is very specific.. it's called from this specific place in django auth:
def create_user(self, username, email=None, password=None, **extra_fields):
"""
Creates and saves a User with the given username, email and password.
"""
now = timezone.now()
if not username:
raise ValueError('The given username must be set')
Can you be 100% positive username is the right value? It sounds like it's an empty string.
I found the error. The error was in indentation of the view.py.
if user is not None:
part of the code should be only if the request type is POST. So that needed indentation.

Django. Error message for login form

I make login/password form:
model:
class LoginForm(forms.Form):
username = forms.CharField(max_length=100)
password = forms.CharField(widget=forms.PasswordInput(render_value=False),max_length=100)
view:
def login_view(request):
if request.method == 'POST':
username = request.POST['email']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None and user.is_active:
login(request, user)
return HttpResponseRedirect("/n1.html")# Redirect to a success page.
return HttpResponseRedirect("/login")
form=LoginForm()
return render(request, 'enter.html', {'login_form': LoginForm})
urls:
(r'^login/$', login_view),
template:
{% if form.errors %}
<p>Something is wrong</p>
{% endif %}
<form class="form-signin" action="" method="post">
<h2 class="form-signin-heading">Login</h2>
{% csrf_token %}
<input class="input-block-level" type="text" name="email" value="" id="email" placeholder="Email">
<input class="input-block-level" type="password" name="password" value="" id="username" placeholder="Password">
<button class="btn btn-large btn-primary" type="submit">Login</button>
<input type="hidden" name="next" value="{{next|escape}}" />
</form>
I use redirect to login page then login or password is wrong, but I want to make error message in this case. Why construction {% if form.errors %} doesn't work? Thx!
Because the form has no idea an error occurred.
When you construct the form here:
form=LoginForm()
You're constructing it without passing it any information. It doesn't know anything about the POST the user just did, or that the the login failed, or that the password was missing, or whatever the error was.
Here's what my login forms look like:
class LoginForm(forms.Form):
username = forms.CharField(max_length=255, required=True)
password = forms.CharField(widget=forms.PasswordInput, required=True)
def clean(self):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if not user or not user.is_active:
raise forms.ValidationError("Sorry, that login was invalid. Please try again.")
return self.cleaned_data
def login(self, request):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
user = authenticate(username=username, password=password)
return user
We override the form's clean method, so that if the form passes validation we can check the user's credentials. We also put a login method on the form object itself, to make our view cleaner.
Next, in our view, we want to do this:
def login_view(request):
form = LoginForm(request.POST or None)
if request.POST and form.is_valid():
user = form.login(request)
if user:
login(request, user)
return HttpResponseRedirect("/n1.html")# Redirect to a success page.
return render(request, 'enter.html', {'login_form': form })
We instantiate the form and hand it the request.POST to check against.
If we have a POST, we check if the form is valid. The form's "clean" method will get called, and check the user credentials for us.
If the credentials fail, we raise an error, which we need to show in our template.
Errors raised by the form (but not attached to a field) are stored in non_field_errors, which can be displayed like so:
{% if form.non_field_errors %}
<ul class='form-errors'>
{% for error in form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
When you redirect, I'm not sure you send the context of your page. So when you redirect to the /login/ page, django tinks it's a new form which is loaded.

Signup then login a user with Django

I have a simple signup form (in signup.html)
<form action="adduser" method="post">
{% csrf_token %}
Email Address: <input type="email" name="email" required autocomplete="on" placeholder="fr#star.com"/><br/>
Username: <input type="text" name="username" maxlength=25 required placeholder="JoyfulSophia"/><br/>
Password: <input type="password" name="password" maxlength=30 required placeholder="**********" /><br/>
<br/>
<input type="submit" value="Send" /> <input type="reset">
</form>
This redirects to the addUser view:
def adduser(request):
u = User.objects.create_user(request.POST['username'], request.POST['email'], password=request.POST['password'])
u.save()
a = Accounts(user=u)
p = Passwords(user=u)
a.save()
p.save()
return HttpResponseRedirect(reverse('OmniCloud_App.views.profile', args=(u.id,)))
Here is the profile:
#login_required
def profile(request, User_id):
u = get_object_or_404(User, pk=User_id)
a = get_object_or_404(Accounts, pk=User_id)
return render_to_response('profile.html', context_instance=RequestContext(request))
So they wouldn't be signed in, but that's okay because we can send you over to /accounts/login?next=/7/ since they are user 7 (Problems Ahead!)
def login(request):
username = request.POST['username']
password = request.POST['password']
user = auth.authenticate(username=username, password=password)
if user is not None and user.is_active:
auth.login(request, user)
return HttpResponseRedirect("/account/profile/")
else:
return HttpResponseRedirect("/account/invalid/")
The request doesn't contain anything called username, but the one which was submitted to the addUser form does, so how can I shoot that bro over to login? I could have it parse the url (which contains the next=USER_ID) but that wouldn't work for someone that just types in base_url/login, and the user_id won't be part of the url forever. So what's a brother to do?
Post data exists only for one request. If you want to use it later you should save it somewhere else.
You could login the user right after registration, in adduser view, he just entered his username and password, he doesn't have to do it again.
And login view is a little off. This is just a "POST" part of the view. You need to check and see if it's GET request and if it is return template with form containing username and password fields and with target url that points to the same view. Something like this:
def login(request):
if request.method == 'GET':
return render_to_response('login.html',
{ 'form': LoginForm() },
context_instance=RequestContext(request))
elif request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = auth.authenticate(username=username, password=password)
if user is not None and user.is_active:
auth.login(request, user)
return HttpResponseRedirect("/account/profile")
else:
return HttpResponseRedirect("/account/invalid/")
Where login.html is something like this:
{% extends "base_site.html" %}
{% block content %}
<form method="post" target="{% url login_view %}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Login" />
</form>
{% endblock content %}
Also, you could return user to the same login form if username and password didn't match and add some message!
This is just from the top of my head, didn't try it, but it should work!
There is an extensible user-registration application for Django called django-registration that offers you a lot of functionality for creating and registering users. Setting it up is very simple, you can find a very good doc here