I'm building a website using Django. I have the register and login sessions working, so any user can create an account and login. But now I want a situation whereby when someone creates an account, the account will be inactive and pending until the admin accepts the user. However, I haven't implemented any code that does that before and I want to know if Django has a built-in package for that. If not, how do I go about it?
If you are using a default User model of Django at time of create user, save it like these:
user = User.objects.create_user(
first_name = first_name,
last_name = last_name,
email = email,
password = password,
username = username,
is_active = False
)
user.save()
and by using filter query list all inactive users to admin.
Related
My goal is to have two views for login: one with email and password, and another with username and password.
Created a custom user class named MyUser extending from AbstractBaseUser. In that user class, stablished
USERNAME_FIELD = 'email'
Django by default uses the username field for authentication purposes of a user.
When i want users to login with email, that's easy now. But how can I do to create another view that logs in with just username and password (instead of the email)?
I do this by adding another authentication backend, using AUTHENTICATION_BACKENDS. Or you can write your own Auth backend, accepting either email or username.
Here's a simple version of an email authentication backend. Note that this requires that e-mail addresses are unique in your database, and does not case fold.
class EmailAuthBackend(ModelBackend):
"""
Email Authentication Backend
Allows a user to sign in using an email/password pair rather than
a username/password pair.
"""
def authenticate(self, request, email=None, password=None, **kwargs):
""" Authenticate a user based on email address as the user name. """
try:
user = User.objects.get(email=email)
except User.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
User().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
I'm using django's authentication to login users. But I have two models from where authenticate method would check the user credentials. One is ApplicationUser and the other is SystemUser I have made one of them and it works fine like so:
models.py
class UserManager(BaseUserManager):
def create_user(self, email, password=None):
"""
Creates and saves a User with the given username and password.
"""
....
return user
def create_superuser(self, email, password):
...
return user
class ApplicationUser(AbstractBaseUser):
application_user_id = models.AutoField(primary_key=True)
....
....
views.py
def login_view(request):
...
user = authenticate(username = email, password = password)
if user is not None:
...
login(request, user)
....
....
I came through this problem and got here but I couldn't work out a solution to this.
My Questions:
How do I specify two AUTH_USER_MODEL, as of yet I have set
ApplicationUser as AUTH_USER_MODEL.
And even if I somehow specify
the two AUTH_USER_MODEL, how do the authenticate or login function
know where (ApplicationUser or SystemUser) to match the credentials and create session for the user
accordingly
In your settings.py set
AUTH_USER_MODEL = 'yourapp.YouCustomUserModel'
Then let's django do the rest.
If you want to have others User Model, you need to extend them from your selected AUTH_USER_MODEL
I need my django users to belong to an Office.
I did the following to extend the default user model:
class UserProfile(models.Model):
user = models.OneToOneField(User)
office = models.ForeignKey('Office')
My post_save signal for the user model calls this function:
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile = UserProfile.objects.create(
user = instance,
office = instance.office
)
I basically want to attach office to "instance". Which means when I create the user I do the following:
user = User(
office = office,
username = username,
email = email,
password = password
)
But I get the error:
'office' is an invalid keyword argument for this function
Which is normal because office is not a field for the User model.
But is there a way to tell django to ignore this field, that this field is only here to "carry" information temporarily?
Just set the office as a simple attribute:
user = User(username=username, email=email)
user.set_password(password)
user.office = office
user.save()
I am using django's inbuilt authentication system. Everything seems to be working fine. There are two fields that the user is requested to input at the time of signup: username and email. While logging in they are required to enter username and password.
I'd like to change this behavior so that username field is gone. I want to treat the email as the users username. So while signing in user will be required to put email / password
Is this possible while still using django's inbuilt auth system? I'm on django 1.7
Update
I had the need to add additional fields so I added the following to models.py
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
telephone_number = models.CharField(max_length=100)
website_url = models.CharField(max_length=100)
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
The answer is directly in django documentation, in short words you should subclass AbstractBaseUser or AbstractUser (in second case you can't totally remove username field), create your own user manager based on BaseUserManager or UserManager and customize built-in auth forms if you're using it (or any app that you're using is using it).
This is not strictly cannon, but to avoid creating a new User class or Auth backend, I tend to let users log in with both username or email.
Anyways you'll want to ensure emails are unique as django does not check this by default.
You'll then have to override the default login view to support this. You can create something along the lines of:
class EmailUsernameLoginView(View):
def post(self, request):
next = request.POST.get('next', None)
username = request.POST.get('username', None)
password = request.POST.get('password', None)
error = ''
if username and password:
try:
usr = User.objects.get(email=username)
username = usr.username
except User.DoesNotExist:
pass # If the user doesn't exist, it's an username
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect(next)
else:
error = 'Your account is not active'
else:
error = 'The username / email - password comb is wrong'
else:
error = 'Please provide a username / email and password'
ctx = {'error': error} # Fill with needed feedback
return render(request, ctx, 'registration/login.html')
This is just a draft and you should probably include a form to help with validation / cleaning
Since it seems that users are allowed to use their usernames to login instead of only email, I want to make the user name default to the email address. How do I achieve this? I'm assuming that I have to override the model somewhere.
Its simple. While you create the User Object, why don't you refer the username to the email..
user = User.objects.create(
username = mail,
email = mail
)
this will do..