Cannot create super user in django - python

I know there are questions in SO regarding this issue. But most questions relates to AbstractBaseUser. I did not find any question with AbstractUser.
PROBLEM:
I want to implement authentication for django project. So I thought of implementing custom user model by inheriting AbstractUser.
Here is my Model:
class User(AbstractUser):
phonenumber = models.CharField(max_length=25,unique=True)
username = models.CharField(max_length=25,default="")
profile_path = models.URLField(max_length=1500)
country = models.CharField(max_length=100,default="")
what_do_you_do = models.CharField(max_length=500,default="")
where_do_you_do = models.CharField(max_length=500,default="")
time_stamp = models.DateTimeField(auto_now_add=True,blank=True)
USERNAME_FIELD = 'phonenumber'
I have added AUTH_USER_MODEL = 'XXX.User' in settings.py . And I thought of creating a super user.
python manage.py createsuperuser
But it is giving me following error:
Traceback (most recent call last):
File "manage.py", line 22, in <module>
execute_from_command_line(sys.argv)
File "/home/sandesh/server/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 367, in execute_from_command_line
utility.execute()
File "/home/sandesh/server/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 359, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/sandesh/server/local/lib/python2.7/site-packages/django/core/management/base.py", line 294, in run_from_argv
self.execute(*args, **cmd_options)
File "/home/sandesh/server/local/lib/python2.7/site-packages/django/contrib/auth/management/commands/createsuperuser.py", line 63, in execute
return super(Command, self).execute(*args, **options)
File "/home/sandesh/server/local/lib/python2.7/site-packages/django/core/management/base.py", line 345, in execute
output = self.handle(*args, **options)
File "/home/sandesh/server/local/lib/python2.7/site-packages/django/contrib/auth/management/commands/createsuperuser.py", line 183, in handle
self.UserModel._default_manager.db_manager(database).create_superuser(**user_data)
TypeError: create_superuser() takes exactly 4 arguments (3 given)

from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class MyUserManager(BaseUserManager):
def create_user(self, phonenumber, password=None):
if not phonenumber:
raise ValueError('Users must have an phonenumber')
user = self.model(
phonenumber=phonenumber,
)
user.save(using=self._db)
return user
def create_superuser(self, phonenumber, password=None):
user = self.model(
phonenumber=phonenumber
)
user.is_admin = True
print(password)
user.set_password(password)
user.save(using=self._db)
return user
class User(AbstractBaseUser):
phonenumber = models.CharField(max_length=25,unique=True)
user= models.CharField(max_length=25,default="")
profile_path = models.URLField(max_length=1500)
country = models.CharField(max_length=100,default="")
what_do_you_do = models.CharField(max_length=500,default="")
where_do_you_do = models.CharField(max_length=500,default="")
time_stamp = models.DateTimeField(auto_now_add=True,blank=True)
is_admin = models.BooleanField(default=False)
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return self.is_admin
objects = MyUserManager()
USERNAME_FIELD = 'phonenumber'
#property
def is_staff(self):
return self.is_admin
def get_short_name():
return self.phonenumber
According to Django docs:
You should also define a custom manager for your User model. If your User model defines username, email, is_staff, is_active, is_superuser, last_login, and date_joined 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:create_user() and create_superuser()
As such, I have provided you a custom manager. Keep your settings as per normal. Note: As shown in your model, you have no password field so I assumed you did not need one in this case.
Also extend from AbstractBaseUser, not AbstractUser.

The problem is in user model created by you.
class User(AbstractUser):
phonenumber = models.CharField(max_length=25,unique=True)
username = models.CharField(max_length=25,default="")
profile_path = models.URLField(max_length=1500)
country = models.CharField(max_length=100,default="")
what_do_you_do = models.CharField(max_length=500,default="")
where_do_you_do = models.CharField(max_length=500,default="")
time_stamp = models.DateTimeField(auto_now_add=True,blank=True)
REQUIRED_FIELDS = ['username']
Add REQUIRED_FIELDS in your model.
One More thing,AbstractUser should be used if you like Django’s User model fields the way they are, but need extra fields.So it means,If you want to use AbstractUser,then you should add new fields in the user Model and not rewrite the predefined fields of Django auth user model. So you need to remove all the fields already inside Django User model or Use AbstractBaseUser for entirely new User Model.
Read further from Here.

You can implementing custom usermodel like this way-:
from django.contrib.auth.models import AbstractBaseUser, UserManager
from django.contrib.auth.models import PermissionsMixin
class User(AbstractBaseUser, PermissionsMixin):
'''
'''
username = models.CharField(max_length=50, null=True)
first_name =models.CharField(max_length=50, null=True)
last_name = models.CharField(max_length=50, null=True)
email = models.EmailField(unique=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
date_joined = models.DateTimeField(default=timezone.now)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', ]
objects = UserManager()

Related

No username attribute of model error, even already have objects = UserManager()?

Here is my model in the user app
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
class UserTable(AbstractBaseUser, PermissionsMixin):
USERNAME_FIELD='email'
objects = UserManager()
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
phone = models.CharField(max_length=255, default=None)
is_active = models.BooleanField(default=False)
Here is my admin.py inside the user app.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import UserTable
admin.site.register(UserTable, UserAdmin)
I also included in my settings.py
INSTALLED_APPS = [
....
'user.apps.UserConfig',
....
]
This is the error when I run python manage.py migrate
(admin.E033) The value of 'ordering[0]' refers to 'username', which is not an attribute of 'user.UserTable'.
The value of 'list_display[0]' refers to 'username', which is not a callable, an attribute of 'UserAdmin', or an attribute or method on 'user.UserTable'.
I dont know why, I thought when I set objects = UserManager() fields like username, first_name, last_name is setted up. I also user USERNAME_FIELD to set email replacing the username primary key.
You are supposed to write ur own UserManager
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
from django.contrib.auth.models import PermissionsMixin
class UserManager(BaseUserManager):
def create_user(self, email, password, **extra_fields):
if not email:
raise ValueError('User must have an email address')
user = self.model(
email=self.normalize_email(email),
**extra_fields
)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
user = self.create_user(
email,
password,
**extra_fields
)
return user
Just a small comment in UserTable model, make
is_active = models.BooleanField(default=True) To be able to login
And in settings.py file add
AUTH_USER_MODEL = 'user.UserTable'
Edit
I noticed that you are calling AbstractBaseUser, BaseUserManager in a wrong way
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
from django.contrib.auth.models import PermissionsMixin
Try it out and told me if there is any problem!
The problem is because you are inheriting from AbstractBaseUser (which does not come with a username field):
class AbstractBaseUser(models.Model):
password = models.CharField(_('password'), max_length=128)
last_login = models.DateTimeField(_('last login'), blank=True, null=True)
... # No definition for usename in this class
and then using UserAdmin (which requires username as field) as your admin:
#admin.register(User)
class UserAdmin(admin.ModelAdmin):
...
# The admin needs the username field as described by ordering
# But your custom user model doesn't have it
ordering = ('username',)
There are a number of ways to fix this, but one way is to define your own model admin for your custom user:
from django.contrib import admin
class MyAdmin(admin.ModelAdmin):
pass
admin.site.register(UserTable, MyAdmin)

Test Django create_user of an AbstractUser without username

I'm trying to test the creation of an user in Django. But my user model is not the standard one (email is the username).
models.py
from django.contrib.auth.models import AbstractUser, UserManager as AbstractUserManager
class UserManager(AbstractUserManager):
def create_user(self, email, password=None, is_active=True, is_staff=False, is_admin=False):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
)
user.set_password(password)
user.save(using=self._db)
return user
class CustomUser(AbstractUser):
objects = UserManager()
username = None
first_name = models.CharField(max_length=150)
last_name = models.CharField(max_length=150)
email = models.EmailField(unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
tests.py
from django.contrib.auth import get_user_model
class CustomUserTests(TestCase):
def test_create_user(self):
user = get_user_model()
utilisateur = user.create_user(
email='test#tester.com',
password='testpass123',
)
self.assertEqual(utilisateur.email, 'test#tester.com')
Error
line 10, in test_create_user
utilisateur = user.create_user( AttributeError: type object 'CustomUser' has no attribute 'create_user'
Something is missing but I don't know how to test well this...
Thanks a lot
CustomUser' has no attribute 'create_user'
create_user is not present on the CustomUser model and that's what the error is saying. The method is present on the UserManager and the manager is defined on the user model as objects = UserManager().
So to access the method, you need to use user.objects.create_user.

'AdminSiteTests' object has no attribute 'user' Django unit tests

I can't seem to figure out why my unit test is failing for the following
Traceback (most recent call last):
File "/app/core/tests/test_admin.py", line 26, in test_users_listed
self.assertContains(res, self.user.name)
AttributeError: 'AdminSiteTests' object has no attribute 'user'
test_admin.py
from django.test import TestCase, Client
from django.contrib.auth import get_user_model
from django.urls import reverse
class AdminSiteTests(TestCase):
def setup(self):
self.client = Client()
self.admin_user = get_user_model().objects.create_superuser(
email='admin#test.com',
password='test123'
)
self.client.force_login(self.admin_user)
self.user = get_user_model().objects.create_user(
email='test#test.com',
password='test123',
name='test name'
)
def test_users_listed(self):
"""Test that users are listed on user page"""
url = reverse('admin:core_user_changelist')
res = self.client.get(url)
self.assertContains(res, self.user.name)
self.assertContains(res, self.user.email)
admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from core import models
class UserAdmin(BaseUserAdmin):
ordering = ['id']
list_display = ['email', 'name']
admin.site.register(models.User, UserAdmin)
models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
class UserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
"""Creates and saves a new user"""
if not email:
raise ValueError('Users must have a email address')
user = self.model(email=self.normalize_email(email), **extra_fields)
# Must encrypt password using set_password() that comes with BaseUserManager
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password):
"""Creates and saves new superuser"""
user = self.create_user(email, password)
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class User(AbstractBaseUser, PermissionsMixin):
"""Custom user model that supports using email instead of username"""
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
I am creating the user in the setup function for the rest of my tests but I'm thinking maybe the setup function isn't getting called to create the user?
All other tests are passing. Including a test that checks whether a user has been created. Any help would be apperciated

Custom User model does not follow with the extended BaseUserManager implementation in django admin

I am a a newbie in django and currently I am exploring with creating Custom User model subclassing the AbstractBaseUser in django. I wrote the following code for the userModel and BaseUserManager implementation.
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.base_user import BaseUserManager
from django.utils import timezone
class AccountManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
values = [email]
field_value_map = dict(zip(self.model.REQUIRED_FIELDS, values))
for field_name, value in field_value_map.items():
if not value:
raise ValueError("The {} value must be set".format(field_name))
email = self.normalize_email(email)
extra_fields.setdefault("username", email) #this line of code here
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):
extra_fields.setdefault("is_staff", False)
extra_fields.setdefault("is_superuser", False)
extra_fields.setdefault("username", email)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password=None, **extra_fields):
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(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_("email address"), unique=True)
username = models.CharField(unique=True, max_length=200)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
is_superuser = models.BooleanField(default=False)
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
address = models.CharField(
max_length=200,
)
latitude = models.FloatField(default=0.00, blank=True)
longitude = models.FloatField(default=0.00, blank=True)
dob = models.DateTimeField(null=True, blank=True, default=timezone.now)
phone = models.CharField(max_length=200, blank=True)
phone_activated = models.BooleanField(default=False)
phone_activation_code = models.CharField(max_length=200)
genderChoices = [("Male", "Male"), ("Female", "Female"), ("Other", "Other")]
gender = models.CharField(max_length=200, choices=genderChoices, default="Male")
profile_image = models.ImageField(blank=True)
cover_photo = models.ImageField(blank=True)
facebook_link = models.CharField(max_length=200, blank=True)
twitter_link = models.CharField(max_length=200, blank=True)
instagram_link = models.CharField(max_length=200, blank=True)
youtube_link = models.CharField(max_length=200, blank=True)
linkedin_link = models.CharField(max_length=200, blank=True)
sendEmail = models.BooleanField(default=True)
sendSMS = models.BooleanField(default=True)
activation = models.CharField(max_length=200)
objects = AccountManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
def __str__(self):
return self.email
I want to have a username field that could be later edited to a custom one, but at the time of creation equals to the email registered with.
Now when I create a superuser from cli all things go fine and I get what I want. But when I create a user with the django admin, the AccountManager class seem like non existent and none of the code here is implemented. i.e username field is stored as empty the first time and gives a non-unique integrity error the other time(of course). Why is the create_user method not called while creating user from django admin??
How can I make it right??
I have of course updated the AUTH_USER_MODEL and have registered the class in admin.py properly. (I'm using django 3.0.10)
As per KenWhitesell in django forums:
The reason that the createsuperuser cli command works is because it specifically calls the create_superuser method on the UserModel.
This is the line from createsuperuser.py:
self.UserModel._default_manager.db_manager(database).create_superuser(**user_data)
However, the Admin facility is designed to be generic, and work with every model. It’s not going to perform actions outside what it can expect to have implemented for every model.
When you look at the docs for managers in the section for adding extra manager methods, it reads in part:
Adding extra Manager methods is the preferred way to add “table-level” functionality to your models. (For “row-level” functionality – i.e., functions that act on a single instance of a model object – use Model methods, not custom Manager methods.)
Since what you’re doing here is a row-level action, a manager method doesn’t apply. To do what you’re trying to do, you may want to override the save method on the model.
Ken
So basically overriding the save method in the CustomModel itself solves the problem.
def save(self, *args, **kwargs):
self.username = self.email
super(CustomUser, self).save(*args, **kwargs)

Django CustomUserModel & Form

After submitting the sign-up form in my Django application, I want to register a User. I want the username to be the email address provided in the form.
To do this I create a CostumUser model, to manage this model I also created a CustomUserManager. see my models.py:
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
from django.utils.translation import ugettext_lazy as _
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils import timezone
from .choices import GENDER_CHOICE
# Create your models here.
class CostumUserManager(BaseUserManager):
def _create_user(self, email, firstName, lastName, gender, password, **extra_fields):
"""
Create and save a user with the given email, password, firstname, lastname and gender
"""
if not email:
raise ValueError("The given Email must be set")
email = self.normalize_email(email)
user = self.model(email=email,
first_name=firstName,
last_name=lastName,
gender=gender,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, firstName, lastName, gender, password=None, **extra_fields):
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
return self._create_user(email, firstName, lastName, gender, password, **extra_fields)
def create_superuser(self, email, firstName, lastName, gender, password, **extra_fields):
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, firstName, lastName, gender, password, **extra_fields)
class CustomUser(AbstractBaseUser):
#CostumUserManager
objects = CostumUserManager()
#CostumUser fields in db.
email = models.EmailField(max_length=250, unique=True)
first_name = models.CharField(max_length=40)
last_name = models.CharField(max_length=40)
gender = models.CharField(max_length=1, choices= GENDER_CHOICE)
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.'
),
)
USERNAME_FIELD = 'email' #Email used as username
#define required fields
REQUIRED_FIELDS = ['first_name','last_name','gender']
def is_staff(self):
return self.staff
def is_actif(self):
return self.actif
I also created a CustomUserCreationForm. see forms.py:
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
from .choices import GENDER_CHOICE
class CustomUserCreationForm(UserCreationForm):
first_name = forms.CharField(max_length=40,
widget=forms.TextInput(attrs={'required':True,#set attributes
'class':'form-control',
'placeholder':'First Name *',
})
)
last_name = forms.CharField(max_length=40,
widget=forms.TextInput(attrs={'required':True,#set attributes
'class':'form-control',
'placeholder':'Last Name *',
})
)
email = forms.EmailField(max_length=254,
widget=forms.TextInput(attrs={'required':True,#set attributes
'class':'form-control',
'placeholder':'Your Email *',
})
)
gender = forms.ChoiceField (choices=GENDER_CHOICE,
widget=forms.Select(attrs={'class':'form-control',
}),
initial='Male',
)
password1 = forms.CharField(widget=forms.PasswordInput(attrs={'required':True,#set attributes
'class':'form-control',
'placeholder':'Password *',
}),
strip=False,
)
password2 = forms.CharField(widget=forms.PasswordInput(attrs={'required':True,#set attributes
'class':'form-control',
'placeholder':'Confirm Password *',
}),
strip=False,
)
class Meta(UserCreationForm):
model = CustomUser
fields = ('email','first_name','last_name','gender')
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = UserChangeForm.Meta.fields
My admin.py looks like:
# Register your models here.
# users/admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import CustomUser
class CustomUserAdmin(admin.ModelAdmin):
model = CustomUser
add_form = CustomUserCreationForm
form = CustomUserChangeForm
admin.site.register(CustomUser, CustomUserAdmin)
When I try to register a superuser, through command:
python manage.py createsuperuser
all the required fields are prompted, after completing all the fields, Django returns an error. (see figure below.)
(personalAppEnv) PS C:\Users\Gebruiker\Desktop\django projects\personalApp\personalApp> python manage.py createsuperuser
Email: super#test.com
First name: Super
Last name: User
Gender: 1
Password:
Password (again):
Traceback (most recent call last):
File "manage.py", line 15, in <module>
execute_from_command_line(sys.argv)
File "C:\Users\Gebruiker\Desktop\django
projects\personalApp\personalAppEnv\lib\site-
packages\django\core\management\__init__.py", line 381, in
execute_from_command_line
utility.execute()
File "C:\Users\Gebruiker\Desktop\django
projects\personalApp\personalAppEnv\lib\site-
packages\django\core\management\__init__.py", line 375, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "C:\Users\Gebruiker\Desktop\django
projects\personalApp\personalAppEnv\lib\site-
packages\django\core\management\base.py", line 316, in run_from_argv
self.execute(*args, **cmd_options)
File "C:\Users\Gebruiker\Desktop\django
projects\personalApp\personalAppEnv\lib\site-
packages\django\contrib\auth\management\commands\createsuperuser.py", line 59, in execute
return super().execute(*args, **options)
File "C:\Users\Gebruiker\Desktop\django
projects\personalApp\personalAppEnv\lib\site-
packages\django\core\management\base.py", line 353, in execute
output = self.handle(*args, **options)
File "C:\Users\Gebruiker\Desktop\django
projects\personalApp\personalAppEnv\lib\site-
packages\django\contrib\auth\management\commands\createsuperuser.py", line 184, in handle
self.UserModel._default_manager.db_manager(database).create_superuser(
**user_data)
TypeError: create_superuser() missing 2 required positional arguments: 'firstName' and 'lastName'
(personalAppEnv) PS C:\Users\Gebruiker\Desktop\django projects\personalApp\personalApp>
Also, when navigating to the signUp form through the browser and sumbitting the form, returns nothing. The form data is not save in the Database, in my views.py I have a line to check if the form is valid -, form.is_valid() this returns True. see views.py:
from django.contrib.auth import login, authenticate
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.views import LoginView, LogoutView
from django.shortcuts import render, redirect
from .forms import CustomUserCreationForm #import signUpForm class to pass to template.
# Create your views here.
def signup(request):
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = CustomUserCreationForm(request.POST)
# check whether it's valid:
if form.is_valid():
print(form.cleaned_data.get('first_name'))
form = CustomUserCreationForm()
return render(request, 'winston/signup.html', {'signUpForm':form,})
else:
print('Not Valid!')
return render(request, 'winston/signup.html', {'signUpForm':form,})
I ran: python manage.py makemigrations and python manage.py migrate which returned:
and
I noticed, after running makemigrations and migrate, the db.sqlite3-journal file does not close. This could be the reason that the database does not update. I think something might be wrong with the model.
if some could give me an explanation or a solution to my peroblem would be appreciated.
I managed to find the issue,
I changed some arguments in the models.py file. As you can see in models.py in the CustomUser class I used class attributes last_name and first_name, while in the class manager I used firstName and lastName. I'm not sure why this would make a difference but it seemed to have changed something as now users and superusers are being save to the database.

Categories

Resources