Below is my custom user model:
class CUserManager(BaseUserManager):
def _create_user(self, email, first_name, password,
is_staff, is_superuser, **extra_fields):
"""
Creates and saves a User with the given email and password.
"""
now = timezone.now()
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
user = self.model(email=email,
first_name = first_name,
is_staff=is_staff, is_active=False,
is_superuser=is_superuser, last_login=now,
date_joined=now, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, first_name, password=None, **extra_fields):
return self._create_user(email, first_name, password, False, False,
**extra_fields)
def create_superuser(self, email, first_name, password, **extra_fields):
return self._create_user(email, first_name, password, True, True,
**extra_fields)
class CUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), max_length=254, unique=True)
first_name = models.CharField(_('first name'), max_length=30)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
is_staff = models.BooleanField(_('staff status'), default=False,
help_text=_('Designates whether the user can log into this admin '
'site.'))
is_active = models.BooleanField(_('active'), default=False,
help_text=_('Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.'))
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
last_updated = models.DateTimeField(_('last updated'), default=timezone.now)
objects = CUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name']
It creates a new user correctly. But when I try to authenticate the user from shell or from views, the authenticate() function doesn't work for users having is_active=False.
>>> from django.contrib.auth import get_user_model, auhtenticate
>>> u = get_user_model()
>>> authenticate(username='abc#gmail.com', password='abc)
The above line returns nothing if the user is inactive but returns the user object otherwise.
I don't understand why its returning nothing for inactive users.
It is happening because of how django's authentication works. By default it uses ModelBackend which checks for is_active https://docs.djangoproject.com/en/1.10/ref/contrib/auth/#django.contrib.auth.backends.ModelBackend.get_user_permissions
So you can create custom authentication backend which will ignore this option
https://docs.djangoproject.com/en/1.10/topics/auth/customizing/#writing-an-authentication-backend
Hi You can write Custom backend for this problem.
from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User
from apps.staffs.models import Staff(Custom User)
class StaffBackend:
# Create an authentication method
# This is called by the standard Django login procedure
def authenticate(self, username=None, password=None):
try:
# Try to find a user matching your username
user = Staff.objects.get(username=username)
# Check the password is the reverse of the username
if check_password(password, user.password):
# Yes? return the Django user object
return user
else:
# No? return None - triggers default login failed
return None
except Staff.DoesNotExist:
# No user was found, return None - triggers default login failed
return None
# Required for your backend to work properly - unchanged in most scenarios
def get_user(self, user_id):
try:
return Staff.objects.get(pk=user_id)
except Staff.DoesNotExist:
return None
Related
This all started when I downloaded coverage.py and started testing my django project. Everything is fine, however I'm lacking coverage on a custom user manager I set up in Models.py
Here's the full code.
models.py
from django.contrib.auth.models import AbstractUser, BaseUserManager
from django.db import models
from django.utils.translation import ugettext_lazy as _
class UserManager(BaseUserManager):
"""Define a model manager for User model with no username field."""
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
"""Create and save a User with the given email and password."""
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra_fields):
"""Create and save a regular User with the given email and password."""
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
"""Create and save a SuperUser with the given email and password."""
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self._create_user(email, password, **extra_fields)
class CustomUser(AbstractUser):
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
# profile_image = models.ImageField(upload_to="users/profile_pic", blank=True)
is_pastor = models.BooleanField(default=True)
home_church = models.ForeignKey(
'church.Church',
on_delete="CASCADE",
blank=True,
null=True)
username = None
email = models.EmailField(_('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager() ## This is the new line in the User model. ##
I'm attempting to test the "_create_user" function in the UserManager. Here is my code
test.py
class UserManagerTestCase(TestCase):
def test_main_create_user(self):
manager = UserManager()
user = manager._create_user('jdoe#gmail.com', 'password123')
self.assertTrue(isinstance(user, User))
Unfortunately, when I call the '_create_user' function I get a Type Error: 'NoneType' object is not callable.
This is strange, because the model manager works as expected when creating users and I confirmed with print statements that both the email and **extra_fields arguments are not None.
Some research online said this might because the Manager is not designed to be called directly. Is that the case? If so, how should you handle unit testing?
Instantiate CustomUser() with values so it can be used to access the methods to be tested.
UserManager CANNOT be used directly, it is only accessible through the
Model it was created for: CustomUser.
#tests.py
class UserManagerTestCase(TestCase):
def test_main_create_user(self):
user = CustomUser.objects.create_user('jdoe#gmail.com', 'password123')
self.assertTrue(isinstance(user, User))
I'd appreciate help with a custom user modul. I set it up analog to this example in the django documentation. I have the following problems:
Login to the admin interface does not work. The login page shows up, but does not accept my credentials after creating an user with ./manage createsuperuser in the shell.
When creating a superuser, it saves initially the password in cleartext. I had a look in the database and found the password in clear text. I guess this comes from create_superuser() where user.set_password() is not used but password=password (as in the example from django docs, so why would they do that?). I changed it in the shell and then it is encrypted. Login still doesnt work tho.
My Code is as following:
authentication/models.py
class UserManager(BaseUserManager):
def create_user(self, email, password=None, **kwargs):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
**kwargs
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password, **kwargs):
user = self.model(
email,
password=password,
**kwargs
)
user.is_admin=True
user.save(using=self._db)
return user
and
class MyUser(AbstractBaseUser):
# use this for auth and sessions
# REQUIRED_FIELDS = ['password']
session = models.ForeignKey(
'sessions.Session',
verbose_name='Session',
blank=True, null=True,
)
email = models.EmailField(unique=True, primary_key=True)
#password = forms.CharField(max_length=30, widget=forms.PasswordInput()) #render_value=False
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
signed_up_since = models.DateTimeField('Signed up since', default=timezone.now())
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
def __str__(self):
return self.email
def get_full_name(self):
return self.email
def get_short_name(self):
return self.email
#property
def is_staff(self):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return self.is_admin
I edited the settings:
AUTH_USER_MODEL = "authentication.MyUser"
I dont use a custom session backend or authentication backends, did the migrations, sqlmigrations etc. Shell gives me this:
>>> user.is_staff
True
Any ideas? Thanks a lot!
The problem is that you are creating a user using self.model() in your create_user method. This leads to the password being saved as plain text.
You should use the create_user method, as in the example in the docs. This will hash the password correctly.
def create_superuser(self, email, password, **kwargs):
user = self.create_user(
email,
password=password,
**kwargs
)
I am trying to build a custom user model in Django. My models.py looks like this:
class UserManager(BaseUserManager):
def _create_user(self, username, email, password, is_staff, is_superuser, **extra_fields):
now = timezone.now()
if not username:
raise ValueError(_('The given username must be set'))
if not email:
raise ValueError(_('The given email must be set'))
email = self.normalize_email(email)
user = self.model(
username=username, email=email,
is_staff=is_staff, is_active=False,
is_superuser=is_superuser, last_login=now,
date_joined=now, **extra_fields
)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, username, email, password=None, **extra_fields):
return self._create_user(username, email, password, False, False, **extra_fields)
def create_superuser(self, username, email, password, **extra_fields):
user=self._create_user(username, email, password, True, True, **extra_fields)
user.is_active=True
user.save(using=self._db)
return user
class User(AbstractBaseUser, PermissionsMixin):
# Standard fields
username = models.CharField(_('username'), max_length=30, unique=True,
help_text=_('Required. 30 characters or fewer. Letters, numbers and #/./+/-/_ characters'),
validators=[
validators.RegexValidator(re.compile('^[\w.#+-]+$'), _('Enter a valid username.'), _('invalid'))
])
first_name = models.CharField(_('first name'), max_length=30, blank=True, null=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True, null=True)
email = models.EmailField(_('email address'), max_length=255)
is_staff = models.BooleanField(_('staff status'), default=False,
help_text=_('Designates whether the user can log into this admin site.'))
is_active = models.BooleanField(_('active'), default=True,
help_text=_('Designates whether this user should be treated as active. Unselect this instead of deleting accounts.'))
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
# Custom fields
is_publisher = models.BooleanField(_('publisher status'), default=False)
# User manager
objects = UserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def get_full_name(self):
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
return self.first_name
def email_user(self, subject, message, from_email=None):
send_mail(subject, message, from_email, [self.email])
Anyway, if I create a super user using the createsuperuser command, everything works fine : the user is created, and the password is hashed properly and secured. However, if I create a user from my admin panel, the user created has his/her password completely exposed. Also the confirm password field doesn't show up, which it does in the regular user model used in Django. How can I solve this problem?
Also, yes I do have AUTH_USER_MODEL = 'myapp.User' in my settings.py.
You need a custom ModelForm and ModelAdmin for creating/ updating User model items.
See: Custom User Models with Admin Site
def home(request):
if request.method == 'POST':
uf = UserForm(request.POST, prefix='user')
upf = UserProfileForm(request.POST, prefix='userprofile')
if uf.is_valid() * upf.is_valid():
userform = uf.save(commit=False)
userform.password = make_password(uf.cleaned_data['password'])
userform.save()
messages.success(request,
'successful Registration',
extra_tags='safe')
else:
uf = UserForm(prefix='user')
return render_to_response('base.html',
dict(userform=uf
),
context_instance=RequestContext(request))
In your views.py try to use this and in forms.py try to get the password from django form. Hope this works
A form with no custom code, and direct access to password field, writes directly on the password field. No call is made to createuser or createsuperuser, so set_password is never called (by default, a ModelForm calls save in the model when called save in it). Recall that writing the user password does not write a secure password (that's why createuser and createsuperuser call set_password somewhere). To do that, avoid writing directly on the field but, instead, calling:
myuserinstance.set_password('new pwd')
# not this:
# myuserinstance.password = 'new pwd'
So you must use custom logic in a custom form. See the implementation for details; you will notice those forms have custom logic calling set_password and check_password. BTW default UserAdmin in Django creates a user in TWO steps: user/password/password_confirm (such password creates), and then whole user data. There's a very custom implementation for that.
I have created a custom user in my django project that inherits from AbstractBaseUser and PermissionsMixin.
class CustomUserManager(BaseUserManager):
def _create_user(self, username, password, is_staff, is_superuser, email=None, **extrafields):
now = timezone.now()
if not username:
raise ValueError("You must specify a username first")
if email:
email = self.normalize_email(email)
user = self.model(username=username, email=email, is_superuser=is_superuser,
is_staff=is_staff, is_active=True, last_login=now,
date_joined=now, **extrafields)
user.set_password(password)
user.save(self._db)
return user
def create_user(self, username, password=None, email=None, **extrafields):
return self._create_user(username, password, False, False, email=email, **extrafields)
def create_superuser(self, username, password, email=None, **extrafields):
return self._create_user(username, password, True, True, email=email, **extrafields)
class MyCustomUser(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=30, unique=True)
email = models.EmailField(_("email address"), max_length=254, unique=True, blank=True, null=True)
first_name = models.CharField(max_length=30, blank=True)
#more custom user fields
I have set the settings attribute
settings.AUTH_USER_MODEL = "users.MyCustomUser"
and used this user as a ForeignKey to another model
class Customer(models.Model):
creator = models.ForeignKey(settings.AUTH_USER_MODEL)
another_model = models.ForeignKey(AnotherModel)
When I run the migrate function it gives me the error described on the title. If i comment out creator field it works (so only the creator foreignkey is causing an issue). I didn't have this problem with sqlite3 and and Django 1.6. I am now in Django 1.8.x and changed to MySQL (locally for developement)and having this issue. Has something changed?
I keep receiving this error when I try to create a user via the createsuperuser management command:
TypeError: 'is_active' is an invalid keyword argument for this function
I have tried adding the is_active field, but to no avail. Also tried messing with the REQUIRED_FIELDS because the django docs say they must match the create_superuser fields. Still no luck.
Your guidance is much appreciated. Thanks! Here is the custom user model I am using:
class CustomUserManager(BaseUserManager):
def _create_user(self, email, password, is_staff, is_superuser, **extra_fields):
"""
Creates and saves a User with the given email and password.
"""
now = timezone.now()
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
user = self.model(email=email,
is_staff=is_staff, is_active=True,
is_superuser=is_superuser, last_login=now,
date_joined=now, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra_fields):
return self._create_user(email, password, False, False, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
return self._create_user(email, password, True, True, **extra_fields)
class Company(models.Model):
company_name = models.CharField(max_length=200)
class CustomUser(AbstractBaseUser):
your_name = models.CharField(max_length=254, blank=True)
company = models.ForeignKey(Company)
email = models.EmailField(blank=True, unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['your_name',]
objects = CustomUserManager()
UPDATED Omitted is_active = True from user = self.model. New error is: *TypeError: 'is_superuser' is an invalid keyword argument for this function*
I ran into the exact same error, following Mike Hibbert's excellent advanced tutorial on defining a Custom User: http://www.mikesdjangotutorials.co.uk/ I was able to get it working by adding those fields to my CustomUser:
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
...I would have assumed they were inherited from AbstractBaseUser, but sure enough, they explain this clearly enough in the docs: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#custom-users-and-django-contrib-admin Note there are a few additional steps described there if you want your CustomUser to work in your Django Admin as well (starting with registering it, etc.)
You should remove every param that you not use in your model (CustomUser) init method and base classes init methods from that call:
user = self.model(email=email,
is_staff=is_staff, is_active=True,
is_superuser=is_superuser, last_login=now,
date_joined=now, **extra_fields)
You have derived CustomUser from AbstractBaseUser that not have init and derived from models.Model. That mean that you can pass to init only names of the fields you’ve defined on your model:
user = self.model(email=email, your_name=something, company=something)
Try to derive CustomUser from AbstractUser