I try to login users from MyUser model in django 1.5. I use e-mail as login, see model:
class MyUser(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
db_index=True,
)
last_name=models.CharField(max_length=30)
first_name=models.CharField(max_length=30)
second_name=models.CharField(max_length=30, blank=True)
post=models.CharField(max_length=30, blank=True)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['last_name','first_name','second_name','post',]
def get_full_name(self):
return self.email
def get_short_name(self):
return self.email
def __unicode__(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.is_admin
And I added LoginForm:
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("/home.html")# Redirect to a success page.
return HttpResponseRedirect("/account/invalid/")# Return a 'disabled account' error message
form=LoginForm()
return render(request, 'enter.html', {'login_form': LoginForm})
template:
{% if form.errors %}
<p>Something is wrong</p>
{% endif %}
<form action="" method="post">
{% csrf_token %}
<label for="email">Login:</label>
<input type="text" name="email" value="" id="email"/>
<label for="password">Password:</label>
<input type="password" name="password" value="" id="username">
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{next|escape}}" />
</form>
urls:
(r'^login/$', login_view),
Problem: It works for users from default User model (username, password), but this form "doesn't know" users from MyUser model (email, password), it redirect them to /account/invalid page.
What am I doing wrong?
Thx!
You need to indicate your custom user model in settings:
AUTH_USER_MODEL = 'myapp.MyUser'
Also, you have to provide custom UserManager, from doc:
You should also define a custom manager for your User model. If your
User model defines username and email fields the same as Django’s
default User, you can just install Django’s UserManager; however, if
your User model defines different fields, you will need to define a
custom manager that extends BaseUserManager providing two additional
methods:
Related
I have extending user profile with profile model and create an post_save signal.
I works well on user creation but seems that there is an issue on update. When I want to update I have messages saying user and email already exists in data table. So nothing is updated. and and send back to Register page but should go to edit_profile page
My model.py:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from authenticate.thumbs import ImageWithThumbsField # transforme les images en thumbs
import os
def image_name(instance, filename):
extension = filename.split('.')
extension = extension[-1]
return 'avatars/{}.{}'.format(instance.user.pk, extension)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
avatar = ImageWithThumbsField(upload_to=image_name, blank=True) # transforme les images en thumbs
bio = models.CharField(max_length=100, blank=True)
location = models.CharField(max_length=30, blank=True, default='Please fill in info')
birth_date = models.DateField(null=True, blank=True)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
My forms.py:
class UniqueUserEmailField(forms.EmailField):
"""
An EmailField which only is valid if no User has that email.
"""
def validate(self, value):
super(forms.EmailField, self).validate(value)
try:
User.objects.get(email = value)
raise forms.ValidationError("Email already exists")
except User.MultipleObjectsReturned:
raise forms.ValidationError("Email already exists")
except User.DoesNotExist:
pass
class SignUpform(UserCreationForm):
"""
Extends the built in UserCreationForm in several ways:
* Adds an email field, which uses the custom UniqueUserEmailField,
that is, the form does not validate if the email address already exists
in the User table.
* The username field is generated based on the email, and isn't visible.
* first_name and last_name fields are added.
* Data not saved by the default behavior of UserCreationForm is saved.
* add forms control from Bootstrap to improve form UX
"""
email = forms.EmailField(required= True, label='', max_length=100, widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Email address' }))
first_name = forms.CharField(label='',max_length=100, widget=forms.TextInput(attrs={'placeholder': 'First Name', 'class': 'form-control'}))
last_name = forms.CharField(label='',max_length=100,widget=forms.TextInput(attrs={'placeholder': 'Last Name', 'class': 'form-control'}))
class Meta:
model = User
fields = ('email', 'username', 'first_name', 'last_name', 'password1', 'password2',)
def __init__(self, *args, **kwargs):
super(SignUpform, self).__init__(*args, **kwargs)
self.fields['username'].widget.attrs['class'] = 'form-control'
self.fields['password1'].widget.attrs['class'] = 'form-control'
self.fields['password2'].widget.attrs['class'] = 'form-control'
# change labels
self.fields['username'].label = ''
self.fields['username'].help_text = '<span class="form-text text-muted"><small>Required.</small></span>'
self.fields['email'].help_text = '<span class="form-text text-muted"><small>Required.</small></span>'
self.fields['password1'].label = ''
self.fields['password1'].help_text = '<ul class="form-text text-muted small">' \
'<li>Your password cannot be too similar to your other personal information.</li>' \
'<li>Your password must contain at least 8 characters.</li>' \
'<li>Your password cannot be a commonly used password.</li>' \
'<li>Your password cannot be entirely numeric.</li>' \
'</ul>'
self.fields['password2'].label = ''
self.fields['password2'].help_text = '<span class="form-text text-muted"><small>Enter the same password as before, for verification.</small></span>'
self.fields['username'].widget.attrs['placeholder'] = 'User Name'
self.fields['password1'].widget.attrs['placeholder'] = 'password'
self.fields['password2'].widget.attrs['placeholder'] = 'confirm password'
def clean_email(self):
# Get the email
email = self.cleaned_data.get('email')
# Check to see if any users already exist with this email as a username.
try:
match = User.objects.get(email=email)
print("ok")
except User.DoesNotExist:
# Unable to find a user, this is fine
return email
# A user was found with this as a username, raise an error.
raise forms.ValidationError('This email address is already in use.')
class EditUseform(UserChangeForm):
class Meta:
model = User
fields = ('email', 'username', 'first_name', 'last_name', 'password',)
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('avatar', 'bio', 'location', 'birth_date')
widgets = {
'birth_date': DatePickerInput(), # default date-format %m/%d/%Y will be used
}
My views.py:
def register_user(request):
if request.method == 'POST':
form = SignUpform(request.POST)
profile_form = ProfileForm(request.POST, request.FILES)
if form.is_valid() and profile_form.is_valid():
form.save()
username = form.cleaned_data['username']
password = form.cleaned_data['password1']
user = authenticate(request, username=username, password=password)
# modify existing profile
profile = Profile.objects.get(user=user.pk)
profile.avatar = profile_form.cleaned_data['avatar']
profile.bio = profile_form.cleaned_data['bio']
profile.location = profile_form.cleaned_data['location']
profile.birth_date = profile_form.cleaned_data['birth_date']
profile.save()
login(request, user)
messages.success(request, 'You are registered')
# redirect to a succes page
return redirect('home')
else:
form = SignUpform()
profile_form = ProfileForm()
context = {'form': form,
'profile_from': profile_form, }
return render(request, 'register.html', context)
def edit_profile(request):
if request.method == 'POST':
form = EditUseform(request.POST, instance=request.user)
profile_form = ProfileForm(request.POST, instance=request.user.profile)
if form.is_valid() and profile_form.is_valid():
form.save()
# modify existing profile
profile_form.save()
messages.success(request, _('Your profile was successfully updated!'))
# redirect to a succes page
return redirect('edit_Profile')
else:
form = EditUseform(instance=request.user)
profile_form = ProfileForm(instance=request.user.profile)
context = {'form': form,
'profile_from': profile_form, }
return render(request, 'edit_Profile.html', context)
My Edit_Profille.html:
{% extends 'base.html' %}
<!---- datepicker ---->
{% block extrahead %}
{{ profile_from.media }}
{% endblock %}
<!-------->
{% block content %}
<h2 class="text-center">Edit user</h2>
<div class="col-md-6 offset-md-3">
<form method="POST" action="{% url 'register' %}" enctype="multipart/form-data">
{% csrf_token %}
{% if form.errors %}
<div class="alert alert-warning alert-dismissable" role="alert">
<button class="close" data-dismiss="alert">
<small><sup>x</sup></small>
</button>
<p>Your form has errors:</p>
{% for field in form %}
{% if field.errors %}
{{ field.errors }}
{% endif %}
{% endfor %}
</div>
{% endif %}
{{ form.as_p }}
{{ profile_from.as_p }}
<input type="submit" value="register" class="btn btn-primary">
</form>
{% endblock %}
I am trying to log a user in, however, my view does not seem to work. The page is rendered and the form is displayed and everything. But when I enter a valid user name and password it just refreshes the page instead of going to success_url. I think it is the way I am implementing my view method. I do not think login(request, user_obj) is being accessed, and if so, so is request.user.is_authenticated().
I also include my login form using
{% if user.is_authenticated %}
{% include 'navbar_in.html' %}
{% else %}
{% include 'navbar_out.html' %}
{% endif %}
It only uses navbar_out.htmlso that is how I know my code is not accessing login(request, user_obj).
User model:
# Create your models here.
class Usermie(models.Model):
# associate fields with django built in user objects
# this provides the authentication that we would need from the django built in utilities
usermie_object = models.OneToOneField(User)
# form fields
id = models.AutoField(primary_key=True)
username = models.CharField(max_length=30, unique=True, blank=False)
email = models.EmailField(max_length=30, unique=True, blank=False, null=False)
first_name = models.CharField(max_length=30, blank=False)
last_name = models.CharField(max_length=30, blank=False)
birthday = models.DateField(blank=False)
password = models.CharField(max_length=50, null=False)
sex = models.CharField(max_length=1, blank=False)
location = models.CharField(max_length=100, null=True)
city = models.CharField(max_length=40, null=True)
province = models.CharField(max_length=40, null=True)
country = models.CharField(max_length=40, null=True)
activated = models.IntegerField() # will be 1 if account is activated, 0 otherwise.
date_created = models.DateTimeField(default=timezone.now) # the time the account is created
date_activated = models.DateTimeField(null=True) # when the account is activated via email
def __str__(self):
return self.username
# create a user object to attach to our forms (SignUp)object
def create_usermie_user_callback(sender, instance, **kwargs):
usermie, new = Usermie.objects.get_or_create(usermie_object=instance)
View:
from .models import Usermie
from django.shortcuts import render
from django.views.generic import View
from .forms import SignUpForm, LoginForm
from django.contrib.auth.models import User
from django.http import HttpResponseRedirect
from django.views.generic.base import TemplateView
from django.contrib.auth import authenticate, login, logout
class UserLoginRegistration(View):
form_class = LoginForm
# Use initial to declare the initial value of form fields at runtime.
# For example, you might want to fill in a username field with
# the username of the current session.
initial = {'key': 'value'}
template_name = 'usermie/usertest.html' # template form will be rendered on
success_url = '/usermie/home/' # template for successfully submitted form
def get(self, request, *args, **kwargs):
form_login = self.form_class(initial=self.initial)
return render(request, self.template_name, {'form_login': form_login})
# method for posting form
def post(self, request, *args, **kwargs):
# Accessing form with post data
form_login = self.form_class(request.POST)
# Checking if user is logged in
if request.user.is_authenticated():
# Making sure user does not log in twice,
# just send user to profile.html if already logged in
return HttpResponseRedirect(self.success_url)
# Checking if the form is valid
if form_login.is_valid():
email = form_login.cleaned_data['email']
password = form_login.cleaned_data['password']
# NB! On Django docs Two methods to authenticate user and log them in
# 1 call authenticate
# 2 call login
# Return a user_obj object if the username and password are valid
# otherwise it will return null, the null variable is called None in python
user_obj = authenticate(email=email, password=password)
if user_obj is not None:
if user_obj.is_active:
login(request, user_obj)
return HttpResponseRedirect(self.success_url)
# If authentication failed
else:
return HttpResponseRedirect(self.template_name)
# If form is not being posted, render form to template
else:
form_login = self.form_class(initial=self.initial)
context = {'form_login': form_login}
return render(request, self.template_name, context)
And this is my mark up
<form class="navbar-form navbar-form-out" action="" method="post">
{% csrf_token %}
{% load widget_tweaks %}
<div class="form-group">
<label class="sr-only" for="{{ form_login.email.auto_id }}">{{ form_login.email.label }}</label>
{% render_field form_login.email class="form-control" placeholder=form_login.email.label %}
</div>
<div class="form-group">
<label class="sr-only" for="{{ form_login.auto_id }}">{{ form_login.password.label }}</label>
{% render_field form_login.password class="form-control" placeholder=form_login.password.label %}
{% for hidden in form_login.hidden_fields %}
{{ hidden }}
{% endfor %}
</div>
<div class="checkbox">
<label>
<input type="checkbox"> Remember me
</label>
</div>
<button type="submit" name="" value="form_login" class="btn btn-default">Sign in</button>
</form>
It might be that your user is not active and you don't handle that case. Try something like:
if user_obj.is_active:
login(request, user_obj)
return HttpResponseRedirect(self.success_url)
else:
return HttpResponse("Your account is inactive.")
I have extendted the UserCreationForm with email and other fields, so that I could authenticate a user with both its username and email.
forms.py:
class UserCreationForm(UserCreationForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'username', 'email',)
views.py:
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('/')
elif:
user = auth.authenticate(email=username, password=password)
if user is not None:
auth.login(request, user)
return HttpResponseRedirect('/')
else:
return HttpResponseRedirect('/accounts/invalid_login')
html:
<form action="/accounts/auth/" method="post">
{%csrf_token%}
<label for="name">Email or Username:</label>
<input type="text" name="name" id="name" value="">
<label for="password">Password:</label>
<input type="password" name="password" id="password" value="">
<input type="submit" value="LOGIN">
</form>
In the views I tried giving both the username and email as input from the form as name, and check to see if username and password authenticate. If not then check whether email and password authenticate. But its not working. How do I solve this problem? Please kindly help me. Thank you.
You need to create an authentication backend: here is mine:
class EmailAuthBackend(ModelBackend):
"""
Email Authentication Backend
Allows a user to sign in using an email/password pair, then check
a username/password pair if email failed
"""
def authenticate(self, username=None, password=None):
""" Authenticate a user based on email address as the user name. """
try:
user = User.objects.get(email=username)
if user.check_password(password):
return user
except User.DoesNotExist:
try:
user = User.objects.get(username=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
""" Get a User object from the user_id. """
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
Then in your settings:
AUTHENTICATION_BACKENDS = ('MyApp.backends.EmailAuthBackend',)
then create a custom view the uses the authenticate function.
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')
I use MyUser model in Django 1.5 (e-mail as login):
class MyUserManager(BaseUserManager):
def create_user(self, email, password=None):
"""
Creates and saves a User with the given email, date of
birth and password.
"""
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=MyUserManager.normalize_email(email),
# date_of_birth=date_of_birth,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password):
"""
Creates and saves a superuser with the given email, date of
birth and password.
"""
user = self.create_user(email,
password=password,
#date_of_birth=date_of_birth
)
user.is_admin = True
user.save(using=self._db)
return user
class MyUser(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
db_index=True,
)
last_name=models.CharField(max_length=30)
first_name=models.CharField(max_length=30)
second_name=models.CharField(max_length=30, blank=True)
about=models.TextField(blank=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['last_name','first_name','second_name',]
def get_full_name(self):
# The user is identified by their email address
return self.email
def get_short_name(self):
# The user is identified by their email address
return self.email
def __unicode__(self):
return self.email
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
#property
def is_staff(self):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return self.is_admin
settings.py:
AUTH_USER_MODEL = 'app.MyUser'
I activated django comments framework:
settings.py:
'django.contrib.comments',
urls:
(r'^comments/', include('django.contrib.comments.urls')),
template (only authorized user can add a comment):
<h2>Add a comment:</h2> {% get_comment_form for post as form %}
<form action="{% comment_form_target %}" method="post" > {% csrf_token %}
{% if next %}
<div><input type="hidden" name="next" value="{{ next }}" /></div>
{% endif %}
{{form.content_type}}{{form.object_pk}}{{form.timestamp}}{{form.security_hash}}
Comment:<br />
{{form.comment}}
<input type="hidden" name="next" value="{{ request.get_full_path }}" />
<input type="submit" name="submit" class="submit-post" value="Post" />
<input type="submit" name="preview" class="submit-preview" value="Preview" />
</form>
{% get_comment_count for post as comment_count %}
<h2>Comments: [{{ comment_count }}]</h2>
{% get_comment_list for post as comment_list %}
{% for comment in comment_list|dictsortreversed:"submit_date" %}
<dl id="comments">
{{ comment.email }} {{ comment.submit_date|date:"d.m.Y G:i" }}
<dd>
{{ comment.comment|striptags|urlizetrunc:20|linebreaksbr }}
</dd>
</dl>
{% endfor %}
How can I get user's model fields 'first_name' and others? comment.email and comment.name gives me 'e-mail' field, comment.first_name gives me nothing. Thx!
According to built-in comment model documentation, you could access a user posted comment via {{ comment.user }} in your template. Consequently, you could access MyUser model fields like this {{ comment.user.email }} or {{ comment.user.first_name }}, etc.