I've been on dj_rest_auth on this project. Trying to add extra fields to the custom user model but it only saves the email and password. I think I have everything right but nothings working.
Heres my user model
class CustomUserManager(BaseUserManager):
"""
Custom user model manager where email is the unique identifiers
for authentication instead of usernames.
"""
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 Email must be set')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
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)
extra_fields.setdefault('is_active', 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):
username = None
email = models.EmailField('email address', unique=True)
USERNAME_FIELD = 'email'
first_name = models.CharField(max_length=30, blank=True)
last_name = models.CharField(max_length=30, blank=True)
phone = models.CharField(max_length=30, blank=True)
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
serializers.py
class UserSerializer(serializers.ModelSerializer):
phone = serializers.CharField(max_length=30, allow_blank=True)
first_name = serializers.CharField(max_length=30, allow_blank=True)
last_name = serializers.CharField(max_length=30, allow_blank=True)
class Meta:
model = CustomUser
fields = ('id', 'email', 'first_name', 'last_name', 'phone')
def save(self, request):
user = super().save(request)
user.phone = self.data.get('phone')
user.first_name = self.data.get('first_name')
user.last_name = self.data.get('last_name')
user.save()
return user
settings.py
AUTH_USER_MODEL = 'users.CustomUser'
REST_AUTH_REGISTER_SERIALIZERS = {
'REGISTER_SERIALIZER': 'users.serializers.UserSerializer',
}
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
and finally in my urls.py
path('register/', RegisterView.as_view()),
From postman I send this post request
{
"email": "ahsan44411#gmail.com",
"password": "ahsan44411",
"password2": "ahsan44411",
"first_name": "ahsan",
"last_name": "mukhtar",
"phone": "64763868"
}
It only saves the email address, phone, first_name, last_name are not saved.
I have searched read nearly every problem on stackoverflow, without any luck, now I am posting here, please inform me if problem is not clear.
You can use the create function to save user data like this. Hope this answer will help you to solve your problem.
def create(self, data):
u = User(username=data["username"], email=data["email"],phone=data["phone"], first_name=data["first_name"],last_name=data["first_name"])
u.set_password(data["password"])
u.save()
return u
Related
I have Django with python-social-auth installed.
My custom user model:
class User(AbstractUser):
"""Custom User model."""
username = None
email = models.EmailField(blank=False, unique=True, verbose_name=_("Email"))
facebook_link = models.URLField(blank=True, verbose_name=_("Facebook profile link"))
contacts = models.CharField(blank=True, max_length=250, verbose_name=_("Contacts"))
hometown = models.CharField(blank=True, max_length=250, verbose_name=_("Hometown"))
start_coordinates = models.CharField(blank=True, max_length=100, verbose_name=_("Start coordinates"))
avatar = ProcessedImageField(
upload_to="avatar/",
format="JPEG",
options={"quality": 80},
default="avatar/default_avatar.jpg",
verbose_name=_("Image"),
)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
def __str__(self):
"""Model representation."""
return self.email
def get_absolute_url(self):
"""Get url to User's model instance."""
return reverse_lazy("public-profile", kwargs={"user_id": self.pk})
def get_full_name(self):
"""Concatenate fist and last names."""
full_name = " ".join([self.first_name, self.last_name])
return full_name.strip()
get_full_name.short_description = _("Full name")
class Meta:
verbose_name = _("User")
verbose_name_plural = _("Users")
Managers.py
class UserManager(BaseUserManager):
"""
Custom user model manager where email is the unique identifiers
for authentication instead of usernames.
"""
def create_user(self, email, password=None, **extra_fields):
"""Create and save a User with the given email and password."""
if not email:
raise ValueError(_("Email required"))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
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)
extra_fields.setdefault("is_active", 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)
I do succesfull authentication with Facebook with this code:
AUTHENTICATION_BACKENDS = (
'social_core.backends.github.GithubOAuth2',
'social_core.backends.google.GoogleOAuth2',
'social_core.backends.facebook.FacebookOAuth2',
'django.contrib.auth.backends.ModelBackend',
)
SOCIAL_AUTH_USER_MODEL = 'accounts.User'
SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL = True
SOCIAL_AUTH_LOGIN_REDIRECT_URL = 'home'
SOCIAL_AUTH_LOGIN_URL = 'login'
SOCIAL_AUTH_FACEBOOK_SCOPE = ['email', 'user_link', 'user_hometown']
SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = {
'fields': 'id, name, email, picture.type(large), link, hometown'
}
SOCIAL_AUTH_FACEBOOK_EXTRA_DATA = [
('name', 'name'),
('email', 'email'),
('picture', 'avatar'),
('link', 'facebook_link'),
('hometown', 'hometown'),
]
As a result, I have a new user instance created in DB with the automatically populated fields:
fist_name, last_name, email.
How do I can populate the rest of fields (facebook_link, hometown) with data from response?
i have a custom user model and i want to create a superuser from a view right, am currently using django restframework, below is my custom model and serializer with the views.
model.py
class CompanyUserManager(UserManager):
def _create_user(self, username, email, password, **extra_fields):
"""
Create and save a user with the given username, email and passsword
"""
if not username:
raise ValueError('The given username must be set')
if not email:
raise ValueError('The email must be set')
email = self.normalize_email(email)
username = self.model.normalize_username(username)
user = self.model(username=username, email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, username: str, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', False)
return self._create_user(username, email, password, **extra_fields)
def create_admin_user(self, username: str, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', False)
extra_fields.setdefault('is_admin', True)
# if extra_fields.get('is_staff') is not True:
# raise ValueError('Super user must have is_staff=True')
# if extra_fields.get('is_admin') is not True:
# raise ValueError('Super user must have is_admin=True')
# if extra_fields.get('is_superuser') is True:
# raise ValueError('Superuser must have is_superuser=False')
return self._create_user(username, email, password, **extra_fields)
def create_superuser(self, username: str, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_admin', True)
if extra_fields.get('is_staff') is not True:
raise ValueError('Super user must have is_staff=True')
if extra_fields.get('is_admin') is not True:
raise ValueError('Super user must have is_admin=True')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True')
return self._create_user(username, email, password, **extra_fields)
# Create your models here.
class CompanyUser(AbstractBaseUser, PermissionsMixin):
username_validator = UnicodeUsernameValidator()
username = models.CharField(_('username'), max_length=150, unique=True, help_text='Required, 150 characters or fewer', error_messages={'unique ': ' a User with this user name is already registered'}, validators=[username_validator])
email = models.EmailField(_('email address'), blank=False, unique=True)
phone = models.CharField(_('phone'), max_length=20, blank=True, null=True)
is_staff = models.BooleanField(_('staff status'), default=True, help_text='Designated user can login using this account')
is_active = models.BooleanField(_('active'), default=True, help_text='Designated whether this user should be treated as active')
is_superuser = models.BooleanField(_('superuser'), default=False, help_text='Designated user can login using this account')
is_admin = models.BooleanField(_('admin'), default=False, help_text='Designated user can login using this account')
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
email_verified = models.BooleanField(_('email_verified'), default=False,)
objects = CompanyUserManager()
EMAIL_FIELD = 'email'
USERNAME_FIELD: str = 'email'
REQUIRED_FIELDS = ['username', 'phone']
#property
def token(self):
token = jwt.encode({
'username': self.username,
'email': self.email,
'exp': datetime.utcnow() + timedelta(hours=24)},
settings.SECRET_KEY, algorithm='HS256')
return token
#property
def staff(self):
return self.is_staff
#property
def admin(self):
return self.is_admin
#property
def active(self):
return self.is_active
#property
def owner(self):
return self.is_superuser
serializer.py
class RegisterSerializer(serializers.ModelSerializer):
# username = serializers.CharField(max_length=100)
# email = serializers.EmailField()
# password = serializers.CharField(max_length=100)
# password2 = serializers.CharField(max_length=100)
# def validate(self, data):
# if data['password'] != data['password2']:
# raise serializers.ValidationError('Passwords must match')
# return data
password = serializers.CharField(max_length=100, write_only=True)
class Meta:
model = CompanyUser
fields = ("id", "username", "email", "password", "is_active")
extra_kwargs = {"password": {"write_only": True}}
def create(self, validated_data):
user = CompanyUser(**validated_data)
user.set_password(validated_data["password"])
user.save()
return user
def create_superuser(self, validated_data):
user = CompanyUser(**validated_data)
print(validated_data)
if "password" in validated_data:
from django.contrib.auth.hashers import make_password
validated_data["password"] = make_password(validated_data["password"])
user.set_password(validated_data["password"])
user.is_superuser = True
user.is_admin = True
user.is_staff = True
user.save()
return user
the create_superuser isnt working, it throws a keyerror password not found
view.py
class RegisterAPIView(GenericAPIView):
"""
A view that allow company owners to create an account
"""
serializer_class = RegisterSerializer
def post(self, request, *args, **kwargs):
serializers = self.serializer_class(data=request.data)
if serializers.is_valid():
serializers.save()
# self.serializer_class.create_superuser(serializers.data)
# serializers.create_superuser(serializers.data)
return Response(serializers.data, status=status.HTTP_201_CREATED)
return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)
so this are my codes and i cant create a superuser from the endpoint, i dont want to use the django cli, any help please 😌
I am trying to createsuper user
when I entered email and password I got this error
File "/mnt/c/Users/ZAKARIA/Desktop/project/env/lib/python3.8/site-packages/django/contrib/auth/management/commands/createsuperuser.py", line 232, in handle
self.UserModel._default_manager.db_manager(database).create_superuser(
TypeError: create_superuser() missing 2 required positional arguments: 'first_name' and 'last_name'
my class managers
from django.contrib.auth.base_user import BaseUserManager
class UserManger(BaseUserManager):
def create_user(self, email, first_name, last_name, password=None):
if not email:
raise ValueError("Users must have an email address")
if not first_name or last_name:
raise ValueError("Users must have a first and last name")
user = self.model(
email=self.normalize_email(email),
first_name=first_name,
last_name=last_name,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email,password, first_name, last_name):
user = self.create_user(
email=self.normalize_email(email),
password=password,
first_name=first_name,
last_name=last_name,
)
user.set_password(user.password)
#user.is_staff = True
user.is_superuser = True
#user.is_admin = True
user.save(using=self._db)
return user
models
import datetime
from django.core.mail import send_mail
from distutils.command.upload import upload
from django.db import models
from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.utils import timezone
from phonenumber_field.modelfields import PhoneNumberField
from .managers import UserManger
GENDER_MALE = "m"
GENDER_FEMALE = "f"
OTHER = "o"
GENDER_CHOICES = (
(GENDER_MALE, "Male"),
(GENDER_FEMALE, "Female"),
(OTHER, "Other"),
)
class User(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
date_of_birth = models.DateField()
first_name = models.CharField(max_length=30, blank=True)
last_name = models.CharField(max_length=30, blank=True)
gender = models.CharField(max_length=1, choices=GENDER_CHOICES, blank=True)
picture = models.ImageField(
upload_to='images/users', null=True, verbose_name="")
is_active = models.BooleanField(default=True)
#is_staff = models.BooleanField(default=False)
phone = PhoneNumberField()
is_admin = models.BooleanField(default=False)
#credits =models.PositiveIntegerField(default=100)
linkedin_token = models.TextField(blank=True, default='')
expiry_date = models.DateTimeField(null=True, blank=True)
objects = UserManger()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name' , 'last_name']
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 __str__(self):
return self.email
def has_perm(self, prem, obj=None):
"Does the user have a specific permission?"
return True
def has_module_perm(self, app_label):
"Does the user have permissions to view the app `app_label`?"
return True
''''
#property
def is_staff(self):
"Is the user a member of staff"
return self.is_admin'''
"""#property
def is_out_of_credits(self):
"Is the user out of credits"
return self.credits > 0
#property
def has_sufficient_credits(self,cost):
return self.credits - cost >= 0
"""
#property
def linkedin_signed_in(self):
return bool(self.linkedin_token) and self.expiry_date > timezone.now()
I have been seeing a lot of questions similar to this but i still don't understand the answers given, some say add positional arguements, I don't quite understand
can any one help me to solve this problem ?
That's probably because you have some extra fields in the UserModel that are not passing accurately in the create_superuser.
Try **extra_fields arg instead of passing first_name, last_name separately, as the docs about Manager methods suggest,
The extra_fields keyword arguments are passed through to the User’s
init method to allow setting arbitrary fields on a custom user model.
So, modify your UserManger class according to this and then this will rectify the problem.
Modified Code:
class UserManger(BaseUserManager):
"""Define a model manager for User model"""
def _create_user(self, email, password=None, **extra_fields):
"""Create and save a User with the given email and password."""
if not email:
raise ValueError('The given email must be set')
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)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password=None, **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)
Now you can set first_name, last_name, as REQUIRED_FIELDS in the UserModel, like this.
REQUIRED_FIELDS = ['first_name' , 'last_name']
For detailed information on BaseUserManager, you can also check Docs
Edit:
After seeing your UserModel, this would be better the use AbstractUser instead of AbstractBaseUser, AbstractUser will carry all the fields that a default Django User has. So you don't have to define the fields like first_name, last_name, is_staff or etc...
That is how you can modify it
# import
from django.contrib.auth.models import AbstractUser
# Model
class User(AbstractUser):
username = None # as you are using email as username
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
date_of_birth = models.DateField()
gender = models.CharField(max_length=1, choices=GENDER_CHOICES, blank=True)
picture = models.ImageField(
upload_to='images/users', null=True, verbose_name="")
phone = PhoneNumberField()
is_admin = models.BooleanField(default=False)
#credits =models.PositiveIntegerField(default=100)
linkedin_token = models.TextField(blank=True, default='')
expiry_date = models.DateTimeField(null=True, blank=True)
objects = UserManger()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name' , 'last_name']
# Do anything else here
missing 2 required positional arguments: 'request' and 'eml'
If you face this error and you use class based view so please remove your self and other parameter which is define in function. Your function need only request as parameter run properly. I am just sharing my experience because I have lost my lot of time behind this error.
def delete(self, request, eml):
print(request.GET.get('d_id'))
return HttpResponse('delete')
It's working fine for me.
def delete(request):
print(request.GET.get('d_id'))
return HttpResponse('delete')
If you use class based view even then remove self parameter from method. I hope it will help you.
Everything worked fine, until I dropped the database and run the migrations again. Now, I'm not able to create superuser again.
The error I got is:
TypeError: create_user() missing 1 required positional argument:
'group'
I create superuser from: python3 manage.py createsuperuser from the terminal.
Anyone faced the same problem and is there any solutions to fix the error?
models.py
class CustomUserManager(BaseUserManager):
def create_user(self, email: str, password: str, group: Group, **extra_fields):
if not email:
raise ValueError(_('The Email must be set'))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
if group is not None:
group.user_set.add(user)
return user
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)
extra_fields.setdefault('is_active', 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):
username = None
email = models.EmailField(_('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
username = models.CharField(max_length=30, blank=True, default='')
is_superuser = models.BooleanField(default=True)
is_admin = models.BooleanField(default=True)
is_employee = models.BooleanField(default=True)
is_headofdepartment = models.BooleanField(default=True)
is_reception = models.BooleanField(default=True)
is_patient = models.BooleanField(default=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=True)
forms.py
class UserForm(ModelForm):
group = forms.ModelChoiceField(queryset=Group.objects.all())
#temp['group']=request.POST.get('group')
#role = forms.ChoiceField(choices=ROLE_CHOICES, label='', widget=forms.RadioSelect(attrs={}))
class Meta:
model = CustomUser
fields = [
'email',
'password',
'group',
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['group'] = ModelChoiceField(
queryset=Group.objects.all(),
empty_label='No group'
)
The create_superuser management command uses the orignal User.objects.create_user function.
You added a positional argument which is required. The create_superuser command does not put any group argument when calling it.
You should make this group argument optional if you really need it.
from typing import Optional
class CustomUserManager(BaseUserManager):
def create_user(self,
email: str,
password: str,
group: Optional[Group] = None,
**extra_fields):
if not email:
raise ValueError(_('The Email must be set'))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
if group is not None:
group.user_set.add(user)
return user
I deleted username field because I wanted user to be able to login with their email address, so I have this in my models.py :
class CustomUser(AbstractUser):
USER_TYPE = ((1, 'HOD'), (2, 'Staff'), (3, 'Student'))
username = None
email = models.EmailField(unique=True)
user_type = models.CharField(default=1, choices=USER_TYPE, max_length=1)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Student(models.Model):
admin = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
gender = models.CharField(max_length=1, choices=GENDER)
address = models.TextField()
profile_pic = models.ImageField(upload_to='media')
session_start_year = models.DateField(null=True)
session_end_year = models.DateField(null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now_add=True)
In my views.py, I tried :
user = CustomUser.objects.create_user(email=email, password=password, user_type=3, first_name=first_name, last_name=last_name)
But I got create_user() missing 1 required positional argument: 'username'
How can I fix this?
You need to write a manager for a custom user model [Django-doc] to reimplement the create_user method.
You can thus implement a CustomUserManager:
from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import UserManager
class CustomUserManager(UserManager):
def _create_user(self, email, password, **extra_fields):
email = self.normalize_email(email)
user = CustomUser(email=email, **extra_fields)
user.password = make_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)
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)
assert extra_fields['is_staff']
assert extra_fields['is_superuser']
return self._create_user(email, password, **extra_fields)
class CustomUser(AbstractUser):
# …
objects = CustomUserManager()
and then you register this manager thus as the objects manager.