I need to send an email using post_save function in django when a new user is created. Authentication and creation is done in the back end itself in views.py,
how do i integrate into the code is as follows -
def signup(request):
if request.method == 'POST':
try:
username = request.POST.get('username')
firstname = request.POST.get('first_name')
password = request.POST.get('password')
lastname = request.POST.get('last_name', '')
email = request.POST.get('email')
contact_num = request.POST.get('mobile_number', '')
try:
user = Customer(username=username, first_name=firstname,
last_name=lastname, email=email, mobile_number=contact_num,
is_staff=False, is_superuser=False,
is_active=True, last_login=now.date(), )
user.set_password(password)
user.save()
user = auth.authenticate(username=username, password=password)
try:
context = {"customer_name": firstname}
html = render_to_string('email_templates/welcome.html', context)
tasks.send_welcome_email(email, html)
except Exception as e:
logger.error("Error while sending Welcome email on signup {}".format(e.message))
except Exception as e:
logger.error("Constraint violation new user Signup", e.message)
c = {}
c.update(csrf(request))
return render(request, 'login.html',
{'user': False, 'c': c, 'Error': 'Username or Email exist already,Try again'})
if user is not None and user.is_active:
auth.login(request, user)
if request.user.is_authenticated():
return HttpResponseRedirect('/')
else:
return HttpResponseRedirect('/accounts/login/')
else:
return HttpResponseRedirect('/404/')
except Exception as e:
logger.error("Exception in new user Signup", e.message)
return HttpResponseRedirect('/500/')
else:
if check_authentication(request):
return HttpResponseRedirect('/404/')
else:
try:
c = {}
c.update(csrf(request))
return render(request, 'login.html', {'user': False, 'c': c})
except Exception as e:
logger.error("Exception in generating csrf for login form", e.message)
return HttpResponseRedirect('/500/')
the above is code for user creation. Any advise on making the code better is also welcome.
IMO, you may send the email using signals, not sending the email directly in the views. This post shows how to use the signals very well.
Also you can use key created of kwargs for checking whether the instance is created or not.
#receiver(post_save, sender=User)
def user_post_save(sender, **kwargs):
if kwargs['created']: # true if the instance is created
# send email for the new user...
Related
I have this code written up and it correctly registers users, though when it comes to the login function, it only works for the superuser i have in the database. Every time I try to log in a user that i greated using the register form, authenticate returns None.
I'm having it print the form data and can confirm that the form being submitted has accurate info, yet it fails authentication every time unless i login the superuser.
Views:
def register(request):
print(request.method)
if request.method == 'POST':
form = reg_form(request.POST)
print(request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
email = form.cleaned_data.get('email')
phone = form.cleaned_data.get('phone')
first_name = form.cleaned_data.get('first_name')
last_name = form.cleaned_data.get('last_name')
user = Users.objects.create(
username=username, email=email,
password=password, phone=phone,first_name=first_name, last_name=last_name
)
try:
user = Users.objects.get(phone=form.cleaned_data.get('phone'))
print("User exists")
except Users.DoesNotExist:
print("DoesNotExist")
return render(request, 'register.html', {'form': reg_form})
login(request, user)
return render(request, 'profile.html')
else:
print(form.errors)
return render(request, 'register.html', {'form': reg_form})
else:
return render(request, 'register.html', {'form': reg_form})
def log_in(request):
if request.method == 'POST':
form = log_form(request.POST)
print(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(request, username=username, password=password)
print(user)
if user is not None:
print("user exists")
login(request, user)
return render(request, 'profile.html')
else:
print("user does not exist")
print(form.errors)
return render(request, 'login.html', {
'form2': log_form
})
else:
return render(request, 'login.html', {
'form2': log_form
})
else:
return render(request, 'login.html', {
'form2': log_form
})
Register form:
class reg_form(ModelForm):
class Meta:
model = Users
fields = '__all__'
widgets = { 'password': forms.PasswordInput(),
}
Login form:
class log_form(forms.Form):
username = forms.CharField(label='username', max_length=64)
password = forms.CharField(widget=forms.PasswordInput)
The password should be hashed: in Django the passwords are not stored in a readable format, but it stores the hash of that password. This concept is discussed in the changing password section of the documentation.
This thus means that for your reg_form, you save the object with:
class reg_form(ModelForm):
class Meta:
model = Users
fields = '__all__'
widgets = { 'password': forms.PasswordInput()}
def save(*args, **kwargs):
user = super().save(*args, **kwargs)
user.set_password(user.password)
return user
This is a very simple version of a more advanced form: the UserCreationForm perhaps it makes more sense, like #iklinac says, to subclass from that form, and slightly alter it to your specific model and fields.
Please check if the user is actually getting created in the database or not if the user is not getting created then make following changes to your register method:
use 'Users.objects.create_user' method instead of 'Users.objects.create', please find below link for more details:
https://docs.djangoproject.com/en/3.2/topics/auth/default/
Also hash your password as Willem is suggesting.
I'm trying to send the email when the user register but it just redirect to the expected page but without sending the email.
Here is my code
def register_view(request): # Creates a New Account & login New users
if request.user.is_authenticated:
return redirect("/")
else:
title = "Register"
form = UserRegistrationForm(request.POST or None)
print(form.is_valid())
if form.is_valid():
user = form.save(commit=False)
password = form.cleaned_data.get("password1")
user.set_password(password)
user.save()
# new_user = authenticate(email=user.email, password=password)
login(request, user)
return redirect("/books")
subject = "Greetings"
msg = "Congratulations Yor Account is created Successfully. Do not share your login credentials with anyone else"
to = "Ak4695755#gmail.com"
res = send_mail(subject, msg, settings.EMAIL_HOST_USER, [to])
context = {"title": title, "form": form}
return render(request, "accounts/signup.html", context)
Since you are return redirect before the message is sent, the rest of the if form.is_valid() statement is executed:
if form.is_valid():
user = form.save(commit=False)
password = form.cleaned_data.get("password1")
user.set_password(password)
user.save()
# new_user = authenticate(email=user.email, password=password)
login(request, user)
subject = "Greetings"
msg = "Congratulations Yor Account is created Successfully. Do not share your login credentials with anyone else"
to = "Ak4695755#gmail.com"
res = send_mail(subject, msg, settings.EMAIL_HOST_USER, [to])
return redirect("/books")
...
I'm attempting to create a new user through a view that implements a subclass of UserCreationForm called ChefRegisterationForm. The test data that has been supplied in a test case has been validated. However if I'm querying for an existing user with Model.get(), I get the following error...
django.contrib.auth.models.DoesNotExist: User matching query does not exist.
I'm not clear on what is causing this error as there is an User.DoesNotExist exception handler defined if the query fails.
forms.py
class ChefRegisterationForm(UserCreationForm):
username = forms.CharField(validators=[validate_username])
def clean(self):
cleaned_data = super().clean()
submitted_username = cleaned_data.get('username')
submitted_password = cleaned_data.get('password1')
if submitted_username == submitted_password:
raise ValidationError(
"Your password cannot be your username.", code="invalid_password"
)
class Meta:
model = User
fields = ['username', 'password1', 'password2']
views.py
def register_chef(request):
if request.method == 'POST':
new_user_form = ChefRegisterationForm(request.POST)
if new_user_form.is_valid():
try:
username = new_user_form.cleaned_data['username']
user = User.objects.get(
username=username
)
except User.DoesNotExist:
user = authenticate(
username=new_user_form.cleaned_data['username'],
password=new_user_form.cleaned_data['password2']
)
login(request, user)
messages.info(f"Logged in: Chef {user}")
return HttpResponseRedirect(reverse("menu:menu_list"))
else:
stored_password = check_password(
new_user_form.cleaned_data['password1'],
user.password
)
if stored_password:
messages.info(
request,
"You already registered an account. Please log in."
)
else:
messages.info(
request,
f"Username {username} exists. Choose another username."
)
return HttpResponseRedirect(reverse("chef:create_chef"))
messages.info(
request,
"Registeration failed. Please try again."
)
new_user_form = ChefRegisterationForm()
return render(request, "chef/register_chef.html", {'form': new_user_form})
test_views.py
class TestCreateNewChef(TestCase):
#classmethod
def setUpTestData(cls):
cls.user_signup_data = {
'username': 'test_chef',
'password1': 'secret',
'password2': 'secret'
}
def test_new_chef_sign_up_success(self):
response = self.client.post(
reverse("chef:register"),
self.user_signup_data,
follow=True
)
self.assertRedirects(response, reverse("menu:menu_list"))
self.assertTemplatedUsed('menu/list_all_current_menus.html')
self.assertContains(
response,
"<p>Logged in: test_chef!</p>",
html=True
)
If user doesn't exists you cannot use authenticate method. Since it will search user and raise DoesNotExist again. You should create new user instead:
except User.DoesNotExist:
user = User.objects.create_user(
username=new_user_form.cleaned_data['username'],
password=new_user_form.cleaned_data['password2'],
email="test#test.com"
)
login(request, user)
messages.info(f"Logged in: Chef {user}")
return HttpResponseRedirect(reverse("menu:menu_list"))
I'm creating a django project for a school, and there are three main kinds of users - parents, teachers, and students. For parents and teachers, I would like them to login using email (they are currently using email logins for a legacy system).
However, for students, I would like them to login using the conventional username approach (since young kids don't have emails). Is this possible to do in Django or is there only one User Authentication model allowed?
You can create separate AuthenticationEmailBackend just for logging by email and add it to AUTHENTICATION_BACKENDS in settings. In this way different AUTHENTICATION_BACKENDS are used as alternatives if authentication fails for previous AUTHENTICATION_BACKENDS.
app/auth.py
from django.contrib.auth import get_user_model
from django.contrib.auth.models import User
class AuthenticationEmailBackend(object):
def authenticate(self, username=None, password=None, **kwargs):
UserModel = get_user_model()
try:
user = UserModel.objects.get(email=username)
except UserModel.DoesNotExist:
return None
else:
if getattr(user, 'is_active', False) and 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
settings.py
AUTHENTICATION_BACKENDS = (
"django.contrib.auth.backends.ModelBackend",
...
"app.auth.AuthenticationEmailBackend",
)
If you leave default django.contrib.auth.backends.ModelBackend in a list users can login by either username or email.
Seems request parameter is needed in authenticate method from Django 1.11:
def authenticate(self, request, username=None, password=None)
According to what is said in Django documentation.
A simple backend which allows you to login with either an email address or a username.
It should be combined with another backend for checking permissions:
settings.py:
AUTHENTICATION_BACKENDS = (
'myproject.accounts.backends.EmailOrUsernameModelBackend',
'django.contrib.auth.backends.ModelBackend' )
account/backends.py:
from django.conf import settings
from django.contrib.auth.models import User
class EmailOrUsernameModelBackend(object):
def authenticate(self, username=None, password=None):
if '#' in username:
kwargs = {'email': username}
else:
kwargs = {'username': username}
try:
user = User.objects.get(**kwargs)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
and for case-insensitive :
class EmailOrUsernameModelBackend(object):
def authenticate(self, username=None, password=None):
# user_model = get_user_model()
if '#' in username:
# kwargs = {'email': username}
field = 'email'
else:
# kwargs = {'username': username}
field = 'username'
try:
case_insensitive_username_field = '{}__iexact'.format(field)
user = User._default_manager.get(**{case_insensitive_username_field: username})
# user = User.objects.get(**kwargs)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
For Django 3.0:
# myapp/backends.py
from django.contrib.auth.backends import BaseBackend
from .models import MyUser
class EmailAuthenticationBackend(BaseBackend):
def authenticate(self, request, **kwargs):
email = kwargs['username'].lower() # If you made email case insensitive add lower()
password = kwargs['password']
try:
my_user = MyUser.objects.get(email=email)
except MyUser.DoesNotExist:
return None
else:
if my_user.is_active and my_user.check_password(password):
return my_user
return None
def get_user(self, user_id):
try:
return MyUser.objects.get(pk=user_id)
except MyUser.DoesNotExist:
return None
This works for Django 2.0 and probably previous versions:
# myapp/backends.py
from django.contrib.auth.backends import ModelBackend
from .models import MyUser
class EmailAuthenticationBackend(ModelBackend):
def authenticate(self, request, **kwargs):
email = kwargs['username']
password = kwargs['password']
try:
my_user = MyUser.objects.get(email=email)
except MyUser.DoesNotExist:
return None
else:
if my_user.is_active and my_user.check_password(password):
return my_user
return None
(Not sure if it is a good idea to extend the ModelBackend, you can crete your own class)
And then, for both versions:
# settings.py
AUTHENTICATION_BACKENDS = [
"django.contrib.auth.backends.ModelBackend",
"myapp.backends.EmailAuthenticationBackend",
]
in models.py
class UserDet(models.Model):
email = models.EmailField(max_length=20)
userName = models.CharField(max_length=20)
in views.py
def user_login(request):
response_data={}
if request.session.has_key('login_id'): #If user already logedin send to dashboard else check userid and password
return render(request, '/dashboard.html')
else:
if request.method == 'POST': # If request method is post then only process request
#print('here in login')
try:
username = request.POST.get('username')
password = request.POST.get('pass')
if '#' in username: #check for email
try:
for u in UserDet.objects.filter(email=username):
#username=u['userName']
username=u.userName
except:
response_data['code']=1000
response_data['status']='fail'
return HttpResponse(json.dumps(response_data), content_type="application/json")
if not request.POST.get('rememberme', None): # check user select the remember me or not if yes then create session that expire after long time
#print('seeing it 0')
request.session.set_expiry(0)
user = authenticate(username=username, password=password) # Check user exist or not
if user: #if user exist then
if user.is_active: #check user is active or not if active then successfully loged in else send error
login(request,user)
update_last_login(None, user)
request.session['login_id'] = user.id
response_data['code']=800
response_data['status']='success'
return HttpResponse(json.dumps(response_data), content_type="application/json")
#return render(request, '/dashboard.html')
else:
response_data['code']=900 #Error for User is not active
response_data['status']='fail'
return HttpResponse(json.dumps(response_data), content_type="application/json")
#return HttpResponse("Your account was inactive.")
else: #Error or Invalid username or password
#print("Someone tried to login and failed.")
#print("They used username: {} and password: {}".format(username,password))
response_data['code']=1000
response_data['status']='fail'
return HttpResponse(json.dumps(response_data), content_type="application/json")
except:
response_data['code']=1001
response_data['status']='fail'
return HttpResponse(json.dumps(response_data), content_type="application/json")
else: #Return to index
return redirect('/', {})
Why the authentication is not working with custom model "Consultants".i have tried a lot but it not working
models.py
class Consultants(models.Model):
# user=models.OneToOneField(User)
consul_id=models.IntegerField(default=0,primary_key=True)
first_name=models.CharField(max_length=255,blank=True,null=True)
last_name=models.CharField(max_length=255,blank=True,null=True)
email=models.EmailField(max_length=255,blank=True,null=True)
username=models.CharField(max_length=255,blank=True,null=True)
password=models.CharField(max_length=50,blank=True,null=True)
consul_pic=models.ImageField(upload_to="/home/cp/Documents/consul_pic",blank=True,null=True)
mobile_no=models.CharField(max_length=255,blank=True,null=True)
)
last_login=models.DateTimeField(default=datetime.now,blank=True,null=True)
is_active=models.BooleanField(default=False)
def __str__(self):
return self.first_name or u''
views.py
def login_user(request):
context = RequestContext(request)
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
print type(username)
try:
user = authenticate(username=username, password=password)
print 'chala'
if user.is_active:
user.backend = 'django.contrib.auth.backends.ModelBackend'
login(request, user)
return HttpResponse("welcome......you are succesfuly log in")
else:
return HttpResponse("Your account is disabled.")
except ObjectDoesNotExist:
return HttpResponse("INvalid User")
else:
return render_to_response('login.html', {}, context)
when i try to authenticate it return None.
it is the correct way which i try to login please help me in it.
that is not correct way of customizing user model
you should try like this
reference : https://docs.djangoproject.com/en/1.9/topics/auth/customizing/
from django.contrib.auth.models import (AbstractBaseUser,
PermissionsMixin,
UserManager)
class Consultants(AbstractBaseUser, PermissionsMixin):
consul_id=models.IntegerField(default=0,primary_key=True)
first_name=models.CharField(max_length=255,blank=True,null=True)
last_name=models.CharField(max_length=255,blank=True,null=True)
email=models.EmailField(max_length=255,blank=True,null=True)
username=models.CharField(max_length=255,blank=True,null=True)
password=models.CharField(max_length=50,blank=True,null=True)
consul_pic=models.ImageField(upload_to="/home/cp/Documents/consul_pic",blank=True,null=True)
mobile_no=models.CharField(max_length=255,blank=True,null=True))
last_login=models.DateTimeField(default=datetime.now,blank=True,null=True)
is_active=models.BooleanField(default=False)
objects = UserManager()
def __str__(self):
return self.first_name or u''