Create this model instance automatically after creating the User model instance - django

I want the UserProfile model object to be created automaticaly when User object is created.
Models.py
class UserManager(BaseUserManager):
def create_user(self, email, username,password=None,passwordconfirm=None):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
username=username,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, password=None):
user = self.create_user(
email,
username=username,
password=password
)
user.is_admin = True
user.is_staff=True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
username=models.CharField(verbose_name='username',
max_length=255,
unique=True,)
password=models.CharField(max_length=100)
account_created=models.DateField(auto_now_add=True,blank=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username','password']
def __str__(self):
return self.username
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
class UserProfile(User):
joined_forums=ArrayField(models.CharField(max_length=100),default=None,blank=True)
user_profile_picture=models.ImageField(upload_to="profile_pictures/",default='user-profile-icon.png')
recent_interactions=ArrayField(ArrayField(models.CharField(max_length=200),size=2,blank=True),blank=True)
Before I had the User instance as foreign key.Now i have removed that and inherited the User class in UserProfile as Multi-table inheritance.Now I am unable to migrate and its asking for default values for the pointer to the User instance.

In order to do what you want to do you have to use post_save signal method of the User Model and once the User Object is saved create the instance of the UserProfile and save it.
https://docs.djangoproject.com/en/4.1/ref/signals/

You can either use signals or you can use django-annoying's AutoOneToOneField. If you are using Signals, add a user field to the UserProfile Model in order to create some form of relationship to your User model. django-annoying's is also a good option.

Related

customising django user model is failing

**Hi
I am trying to customize the django default user. Applying migrations works fine. However I get an error when i try to create a super user. Can you please advise why I get this error?
******************** self.UserModel._default_manager.db_manager(database).create_superuser(**user_data)
File "/home/gravityns/PycharmProjects/dev/shop/models.py", line 54, in create_superuser
user.is_staff = True
AttributeError: can't set attribute
# accounts.models.py
from django.db import models
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser
)
from django.core.validators import RegexValidator
class UserManager(BaseUserManager):
def create_user(self, username, password, email):
"""
Creates and saves a User with the given email and password.
"""
if not username:
raise ValueError('Users must have a username')
if not email:
raise ValueError('Users must have an email address')
user = self.model(
username = username,
email = self.normalize_email(email),
)
user.set_password(password)
user.save(using=self._db)
return user
def create_staffuser(self, username, password, email):
"""
Creates and saves a staff user with the given email and password.
"""
user = self.create_user(
username,
email,
password,
)
user.is_staff = True
user.save(using=self._db)
return user
def create_superuser(self, username, password, email):
"""
Creates and saves a superuser with the given email and password.
"""
user = self.create_user(
username,
email,
password
)
user.is_staff = True
user.is_admin = True
user.save(using=self._db)
return user
USERNAME_REGEX = '^[a-zA-Z0-9.#+-]*$'
class User(AbstractBaseUser):
username = models.CharField(max_length=255, validators=[
RegexValidator(regex= USERNAME_REGEX,
message = 'Username must be Alphanumeric or any of the following: ". # + -"')],
unique=True
)
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
created_at = models.DateField(auto_now_add=True, blank=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False) # a admin user; non super-user
# notice the absence of a "Password field", that's built in.
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email'] # Email & Password are required by default.
objects = UserManager()
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 __str__(self): # __unicode__ on Python 2
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?"
return self.is_staff
#property
def is_admin(self):
"Is the user a admin member?"
return self.is_admin
#property
def is_active(self):
"Is the user active?"
return self.is_active
You're overwriting the normal is_staff attribute with your custom property. You need to rename those properties so that they don't clash with the stuff AbstractBaseUser already implements. Look at how that class implements is_staff and others etc here: https://github.com/django/django/blob/master/django/contrib/auth/models.py#L288
You have a field on User model as User.is_staff and a #property with the same name. So you can't set the property of the model object by user_instance.is_staff = True.
You can have is_staff as a field or as a class property, not both.
You have unncessarily defined properties for is_staff, is_active and is_superuser. But those are already fields, with the exact same name. Therefore, when you try and set user.is_staff = True, Python access your property, and tries to "set" that, rather than the field.
There is no reason to do this. The only reason you would need to define those properties is if you want to disallow setting the fields themselves. But you don't want to do that. (Alternatively, if you didn't want fields at all, but wanted to base the value on some custom logic - but, again, you wouldn't be able to set them unless you defined a custom setter.)
Remove all three of those properties.

django custom user model password is not being hashed

I have my own custom User model, and its own Manger too.
models:
class MyUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True)
first_name = models.CharField(max_length=35)
last_name = models.CharField(max_length=35)
username = models.CharField(max_length=70, unique=True)
date_of_birth = models.DateField()
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
#property
def is_staff(self):
return self.is_admin
def get_full_name(self):
return ('%s %s') % (self.first_name, self.last_name)
def get_short_name(self):
return self.username
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'username', 'date_of_birth']
manager:
class MyUserManager(BaseUserManager):
def create_user(self, email, first_name, last_name, username, date_of_birth, password=None, **kwargs):
if not email:
raise ValueError('User must have an email address')
user = self.model(
email=self.normalize_email(email),
first_name=first_name,
last_name=last_name,
username=username,
date_of_birth=date_of_birth,
**kwargs
)
user.set_password(self.cleaned_data["password"])
user.save(using=self._db)
return user
def create_superuser(self, email, first_name, last_name, username, date_of_birth, password, **kwargs):
user = self.create_user(
email,
first_name=first_name,
last_name=last_name,
username=username,
date_of_birth=date_of_birth,
password=password,
is_superuser=True,
**kwargs
)
user.is_admin = True
user.save(using=self._db)
return user
Everything works when creating a new user without any errors. But when I try to login I can't. So I checked the user's password to confirm and the password is displayed as plain text strongpassword, and when changed admin form to get the hashed password using ReadOnlyPasswordHashField I get an error inside the password field, even though I used set_password() for the Manger inside the create_user() function.
Invalid password format or unknown hashing algorithm
However, if I manually do set_password('strongpassword') for that user it is then hashed. Could you please help me solve this problem. Thank you.
It looks like you created a user in a way that does not use your manager's create_user method, for example through the Django admin.
If you create a custom user, you need to define a custom model form and model admin that handles the password properly.
Otherwise, passwords will not hashed when a user is created through the Django admin.
The example in docs for creating a custom users shows how to create the model form and model admin.
I know it's too late now, but I'll just post this for future reference.
If you're creating a new user by calling the save function on its serializer, you'll need to override the create function of the serializer as shown below, (which is pretty obvious, but I got stuck on it for a little bit....)
class SignUpView(views.APIView):
authentication_classes = ()
permission_classes = (permissions.AllowAny,)
def post(self, request, format=None):
serializer = UserSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(
min_length=6, write_only=True, required=True)
class Meta:
model = User
fields = (
'id', 'email', 'password', 'is_staff',
'is_active', 'date_joined')
def create(self, validated_data):
return User.objects.create_user(**validated_data)
Late answer but anyway, you need to make Custom User Model form too with explicit hashing.
Else just make form inheriting UserCreationForm like:
from .models import MyUser
from django.contrib.auth.forms import UserCreationForm
class UserForm(UserCreationForm):
class Meta:
model = User
fields = ['email']
Add this in your UserSerialzer.
Basically you have to override the create method in order to hash the password.
def create(self,validated_data):
user = User.objects.create(email = validated_data['email'])
user.set_password(validated_data['password'])
user.save()
return user

django admin not working with custom user

I feel like I'm missing somehting obvious on this one.
I've created a custom user and user manger
class UserManager(BaseUserManager):
# create a normal user
# an email and password must be provided
def create_user(self, email, password, first_name, last_name,
location, date_of_birth):
if not email:
raise ValueError("User must have an email")
if not password:
raise ValueError("User must have a password")
email = email.lower()
user = self.model(
email=email,
first_name=first_name,
last_name=last_name,
location=location,
date_of_birth=date_of_birth
)
user.set_password(password)
user.save(using=self._db)
return user
# Make an administrator
def create_superuser(self, email, password, first_name, last_name,
location, date_of_birth):
user = self.create_user(
email=email,
password=password,
first_name=first_name,
last_name=last_name,
location=location,
date_of_birth=date_of_birth
)
user.is_admin = True
user.is_moderator = True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True
)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
location = models.ForeignKey(Location)
date_of_birth = models.DateField()
date_joined = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_moderator = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'location', 'date_of_birth']
def __unicode__(self):
return self.email
def get_full_name(self):
return self.first_name + ' ' + self.last_name
def get_age(self):
age = date.today() - self.date_of_birth
return age.days / 365
def is_staff(self):
return self.is_admin
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
However if I visit the admin site, It will happily authorize a user who is not an admin is_admin=False
Has anyone run into this problem, Is there something I need to change when using django admin with a custom user?
EDIT
setting.py
AUTH_USER_MODEL = 'userAccount.User'
AUTHENTICATION_BACKEND = (
'django.contrib.auth.backends.ModelBackend',
)
is_admin is not something that django's authentication system knows about. In the authentication form that is used, it is only checking if the user is active or is staff:
class AdminAuthenticationForm(AuthenticationForm):
"""
A custom authentication form used in the admin app.
"""
error_messages = {
'invalid_login': _("Please enter the correct %(username)s and password "
"for a staff account. Note that both fields may be "
"case-sensitive."),
}
required_css_class = 'required'
def confirm_login_allowed(self, user):
if not user.is_active or not user.is_staff:
raise forms.ValidationError(
self.error_messages['invalid_login'],
code='invalid_login',
params={'username': self.username_field.verbose_name}
)
In the original user model, is_staff is a model field. You do not have such a field, but rather a method. This could be a why its not working.
You can solve this problem two ways:
Create your own AdminAuthenticationForm and adjust the confirm_login_allowed method to check for is_admin rather than is_staff.
Create a is_staff property in your custom user model:
#property
def is_staff(self):
return self._is_admin

Why is Django giving me: 'first_name' is an invalid keyword argument for this function?

I'm trying to create a custom user profile and have modified the example only slightly
from django.conf import settings
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
class MyUserManager(BaseUserManager):
def create_user(self, email, password=None, first_name=None, last_name=None):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=MyUserManager.normalize_email(email),
first_name=first_name,
last_name=last_name,
#date_of_birth=date_of_birth,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password, first_name=None, last_name=None):
user = self.create_user(email,
password=password,
first_name=first_name,
last_name=last_name,
#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,
)
first_name=models.CharField(max_length = 30),
last_name=models.CharField(max_length = 30),
#date_of_birth = models.DateField()
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
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
When I try to run syncdb I get the following error:
You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Email address: uou#pce.com
Password:
Password (again):
TypeError: 'first_name' is an invalid keyword argument for this function
I have struggled to debug this because of the limited nature of the error message. I feel I'm making a simple mistake what am I doing wrong?
You are trying to set None (Null) value into first_name and it seems that this property don't allow it.
Try this changes:
class MyUserManager(BaseUserManager):
def create_user(self, email, password=None, first_name='', last_name=''):
In model:
first_name=models.CharField(max_length = 30, blank = True)

Django 1.5. Users profile creation

I use django 1.5 with custom model MyUser. I want to make users profile page, where he can modify only one field - 'about'.
I tried something like that:
forms.py:
class UserSettingsForm(forms.ModelForm):
class Meta:
model = get_user_model()
fields = ('about')
view.py:
class UserSettings(UpdateView):
form_class = UserSettingsForm
template_name = "user/settings.html"
def get_object(self, queryset=None):
return self.request.user
def get_success_url(self):
return reverse('user_detail', args=[self.request.user.username])
urls:
url(r'^settings/$', UserSettings.as_view(), name='user_settings')
model:
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)
about=models.TextField(blank=True)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['last_name','first_name','about']
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
But I got error: django.core.exceptions.ImproperlyConfigured: AUTH_USER_MODEL refers to model 'app.MyUser' that has not been installed
How can I make users profile in django 1.5? Thx!
MyUser class should be under the application named 'app' in your settings file in order for the auth framework to pick it.