I have my super basic authentication app, and I tried to write a simple Registration with email, first name, last name and (logically) password, but it seems that when I enter my request data it is "lost" somewhere. When I press the "POST" button, all the fields are blank and it says: "This field is required". I've been trying to figure it out for quite a long time, but I am new to django. I hope you can spot the problem.
Here is my models.py:
class UserManager(BaseUserManager):
def create_user(self, first_name, last_name, email, password=None):
if first_name is None:
raise TypeError('Users must have a first name')
if last_name is None:
raise TypeError('Users must have a last name')
if email is None:
raise TypeError('Users must have an email')
user = self.model(email=self.normalize_email(email), first_name=first_name, last_name=last_name)
user.set_password(password)
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(db_index=True, unique=True)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
is_active = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name']
objects = UserManager
My serializers.py:
class RegistrationSerializer(serializers.ModelSerializer):
token = serializers.CharField(max_length=255, read_only=True)
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'password', 'token']
def create(self, validated_data):
return User.objects.create_user(**validated_data)
And my views.py:
class RegistrationAPIView(APIView):
permission_classes = (AllowAny,)
serializer_class = RegistrationSerializer
def post(self, request):
user = request.data.get('user', {})
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
Related
I am trying to create a user profile, i followed through a tutorial which has registration for only username, email and password but i want to be able to add other custom fields.
What i did:
Models.py:
class UserManager(BaseUserManager):
def create_user(self, username, email, password=None,):
if username is None:
raise TypeError('User should have a userame')
if email is None:
raise TypeError('Users should have a Email')
user = self.model(username=username , email = self.normalize_email(email))
user.set_password(password)
user.save()
return user
def create_superuser(self, username, email, password=None):
if password is None:
raise TypeError('User should have a password')
user=self.create_user(username,email,password)
user.is_superuser = True
user.is_staff = True
user.save()
return user
class User(models.Model):
dso = models.ForeignKey(Dso,related_name='dso',default=NULL,blank=False,on_delete=models.CASCADE)
name = models.CharField(max_length=70, blank=False, default='')
email = models.EmailField(max_length=70, blank=False, default='')
password = models.CharField(max_length=70, blank=False, default='')
address = models.CharField(max_length=70, blank=False, default='')
roleId = models.IntegerField(blank=False, default='1')
isActive = models.BooleanField(blank=False, default=True)
customerId = models.CharField(max_length=70, blank=False, default='')
dateJoined = models.DateTimeField(auto_now_add=False, blank=False, default=NULL)
#property
def energy_data(self):
energydata = EnergyData.objects.filter(customerId=self.customerId).first()
return energydata
Serializers.py:
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(max_length = 68, min_length=6, write_only = True)
class Meta:
model=User
fields=['email','username','password','name','address','customerId',
'dso', 'roleId']
def validate(self, attrs):
email = attrs.get('email', '')
username = attrs.get('username', '')
if not len(username) >= 4:
raise serializers.ValidationError('Username must be morethan 4 letters or characters')
return attrs
def create(self, validated_data):
return User.objects.create_user(**validated_data)
Views.py:
class RegisterView(generics.GenericAPIView):
serializer_class= RegisterSerializer
def post(self, request):
user = request.data
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True)
serializer.save()
user_data = serializer.data
user= User.objects.get(email=user_data['email'])
token = RefreshToken.for_user(user).access_token
current_site = get_current_site(request).domain
relativeLink = reverse('email-verify')
absolute_url = 'http://'+current_site+relativeLink+"?token="+str(token)
email_body= 'Hi '+ user.username + ' Use this link below to verify your email \n'+ absolute_url
data = {'email_subject': 'Verify Your Email', 'email_body': email_body , 'to_email': user.email}
Util.send_email(data)
return Response(user_data, status = status.HTTP_201_CREATED)
URL Path:
path('register/', RegisterView.as_view(), name="register" )
When i do this and try to test i get the error, 'UserManager.create_user() got an unexpected keyword argument 'name''
Please kindly help as i am new to django rest frameworrk.
In your serializers.py you have the fields list that includes the variable 'name', but it is never defined in the models.py
Try to change serializers.py
fields=['email','username','password','address','customerId',
'dso', 'roleId']
And modify the variable name in models.py to be username instead of name
username = models.CharField(max_length=70, blank=False, default='')
Based on my experience with Django having a Model called "user" is going to create problems at some point since Django already have a User model pre-installed in the backend.
I know this is not the exact answer you were looking for, this will probably spare you a headache in the future.
To create a user profile I created the following model linking the User model with a OneToOneField.
class Profile(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
bio = models.TextField()
profile_pic = models.ImageField(null=True, blank=True,upload_to="images/")
def __str__(self):
return str(self.user)
and obvioulsy imported
from django.contrib.auth.models import User
As a result,
I would remove your User model
Import "from django.contrib.auth.models import User"
add to the first line of your
UserManager Model, I would add
"user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
I'm using a custom User created with AbstractBaseUser and I tried to add users to a specific group using the django admin. But there were no option to add users to a group. So I found a solution from the stack overflow and It gave me the capability to add users to the group I created. But after saving the user It gives me an error saying Group object has no attribute user_set
My User Model
class MyAccountManager(BaseUserManager):
def create_user(self, email, username, password=None):
if not email:
raise ValueError("Users must have an email address")
if not username:
raise ValueError("Users must have an username")
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):
user = self.create_user(
email=self.normalize_email(email),
username=username,
password=password,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
email = models.EmailField(verbose_name='email', max_length=80, unique=True)
username = models.CharField(max_length=30, unique=True)
first_name = models.CharField(max_length=100,null=True)
last_name = models.CharField(max_length=100,null=True)
phone_no = models.CharField(max_length=12,null=True)
date_joined = models.DateField(
verbose_name='date joined', auto_now_add=True)
last_login = models.DateField(verbose_name='last login', auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = MyAccountManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
Code I got from the stackoverflow
User = get_user_model()
# Create ModelForm based on the Group model.
class GroupAdminForm(forms.ModelForm):
class Meta:
model = Group
exclude = []
# Add the users field.
users = forms.ModelMultipleChoiceField(
queryset=User.objects.all(),
required=False,
# Use the pretty 'filter_horizontal widget'.
widget=FilteredSelectMultiple('users', False)
)
def __init__(self, *args, **kwargs):
# Do the normal form initialisation.
super(GroupAdminForm, self).__init__(*args, **kwargs)
# If it is an existing group (saved objects have a pk).
if self.instance.pk:
# Populate the users field with the current Group users.
self.fields['users'].initial = self.instance.user_set.all()
def save_m2m(self):
# Add the users to the Group.
self.instance.user_set.set(self.cleaned_data['users'])
def save(self, *args, **kwargs):
# Default save
instance = super(GroupAdminForm, self).save()
# Save many-to-many data
self.save_m2m()
return instance
Why this is giving me the error and is there any solutions for this
Thank You!
Django implements group relation in PermissionsMixin so you don't have that particular relation
You can implement AbstractUser class instead or add the Mixin
class User(AbstractBaseUser, PermissionsMixin):
The employees field is a list of users which are employees of the user. Every user can have every user as employee, a user can also be an employee and have employees.
I have a problem where it automatically adds the user as an employee to all the employees added to the user. So when you add user 2 as employee to user 1, it also adds user 1 as employee of user 2.
How can I make it so it doesn't change other records? I simply want to add employees to the user being added.
I'm using Django REST 2.2. The employees field is a ManyToMany field, is this correct for my usage?
users/models.py
class MyUserManager(BaseUserManager):
def create_user(self, email, password=None):
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
def create_superuser(self, email, password):
user = self.create_user(
email=self.normalize_email(email),
password=password,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class CustomUser(AbstractBaseUser):
username = None
email = models.EmailField(verbose_name='email address', max_length=255, unique=True)
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_employee = models.BooleanField('is_employee', default=False)
employees = models.ManyToManyField("self", related_name='employees', blank=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = MyUserManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(selfself, app_label):
return True;
users/serializers.py
class CustomUserSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ('id', 'email', 'password', 'is_employee', 'employees')
def create(self, validated_data):
validated_data['password'] = make_password(validated_data.get('password'))
return super(CustomUserSerializer, self).create(validated_data)
def update(self, instance, validated_data):
instance.email = validated_data.get('email')
instance.set_password(validated_data.get('password', instance.password))
instance.is_employee = validated_data.get('is_employee')
instance.employees.set(validated_data.get('employees'))
instance.save()
return instance
Try to set ManyToManyField.symmetrical to False
ManyToMany relation is wrong for your case. Cause a user can't be an employee of several employers, can only be an employee of a single employer.
So, you should simply create a many-to-one relationship:
class CustomUser(AbstractBaseUser):
...
employer = models.ForeignKey('self', related_name='employees', on_delete=models.SET_NULL)
So, each user will have a single employer field, and employees set. And you can probably get rid of is_employee field since you can check if a user is an employee by just checking if employer field is set.
Email field in the Django(3.0) Custom User Model is case sensitive, I tried various ways to make it case-insensitive but no success so far.
Code
forms.py
class UserCreationForm(UserCreationForm):
class Meta:
model = User
fields = ('first_name','last_name','username','email','password1','password2')
class UserChangeForm(UserChangeForm):
class Meta:
model = User
fields = ('first_name','last_name','username','email',)
class UserUpdateForm(forms.ModelForm):
'''
model form are the form that work with specific user model
'''
class Meta:
model = User
fields = ('first_name','last_name','username','email',)
class ProfileUpdateForm(forms.ModelForm):
'''
model form are the form that work with specific user model
'''
class Meta:
model = Profile
fields = ['image']
manager.py
class UserManager(BaseUserManager):
def create_user(self, email, username, first_name, last_name, password=None):
if not email:
raise ValueError('Must have Email')
if not username:
raise ValueError('Must have username')
if not first_name:
raise ValueError('Must have first_name')
if not last_name:
raise ValueError('Must have last name')
user = self.model(
email=self.normalize_email(email),
username=username,
first_name=first_name,
last_name=last_name,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, first_name, last_name, password=None):
user = self.create_user(
email=email,
username=username,
first_name=first_name,
last_name=last_name,
password=password,
)
user.is_active = True
user.is_staff = True
user.is_admin = True
user.is_superuser = True
user.save(using=self._db)
return user
Model.py
class User(AbstractBaseUser):
# compulsory fields
email = models.EmailField(max_length=255, unique=True)
username = models.CharField(
unique=True, max_length=255, null=True, blank=False)
first_name = models.CharField(
unique=False, max_length=255, null=True, blank=False, verbose_name='First Name')
last_name = models.CharField(
unique=False, max_length=255, null=True, blank=False, verbose_name='Last Name')
date_joined = models.DateTimeField(default=timezone.now)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'username']
objects = UserManager()
def __str__(self):
return f'{self. username}'
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return self.is_admin
class Profile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
there are two models that interact with User, one is User and other is Profile. (Profle handles images)
Things already tried
One of the very obvious things to try is to make email lowercase in manager.py before any authentication and so I did like this
manage.py (modified)
user = self.model(
email=self.normalize_email( **email.lower()** ), # <- notice change here
username=username,
first_name=first_name,
last_name=last_name,
)
user = self.create_user(
email=email.lower() , # <-- notice change here
username=username,
first_name=first_name,
last_name=last_name,
password=password,
)
but this didn't work.
Second was this post, this is another StackOverflow post which I followed which didn't work either
I am trying to solve this problem for hours and can't think of anything else, would really appreciate some advice.
I've checked other questions with same problem and tried solving with the solutions but none helped.
I neither see 'First Name' nor 'Last Name' input while creating a super user in the terminal
I've been following this tutorial 'https://www.youtube.com/watch?v=HshbjK1vDtY&t=3422s' but the tutor doesn't face any problem while doing the exactly same thing I'm doing so there's nowhere I could find solution
This is my models.py
from django.db import models
from django.contrib.auth.models import(
AbstractBaseUser, BaseUserManager
)
class UserManager(BaseUserManager):
def create_user(self, first_name, last_name, email, password=None, is_active=True, is_staff=False, is_admin=False):
if not first_name:
raise ValueError("Users must have an first name")
if not last_name:
raise ValueError("Users must have an last name")
if not email:
raise ValueError("Users must have an email address")
if not password:
raise ValueError("Users must have a password")
user = self.model(
email=self.normalize_email(email)
)
user.first_name = first_name
user.last_name = last_name
user.set_password(password)
user.staff = is_staff
user.admin = is_admin
user.active = is_active
user.save(using=self._db)
return user
def create_staffuser(self, email, first_name, last_name, password=None):
user = self.create_user(
email,
first_name,
last_name,
password=password,
is_staff=True
)
return user
def create_superuser(self, email, first_name, last_name, password=None):
user = self.create_user(
email,
first_name,
last_name,
password=password,
is_admin=True,
is_staff=True
)
return user
class User(AbstractBaseUser):
first_name = models.CharField(max_length=50, blank=True, null=True)
last_name = models.CharField(max_length=50, blank=True, null=True)
email = models.EmailField(max_length=254, unique=True)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False)
admin = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELD = ['first_name', 'last_name']
objects = UserManager()
def __str__(self):
return self.email
def get_first_name(self):
return self.first_name
def get_last_name(self):
return self.last_name
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.staff
#property
def is_admin(self):
return self.admin
#property
def is_active(self):
return self.active
I've imported this in admin.py
admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from .forms import UserAdminChangeForm, UserAdminCreationForm
from .models import User
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
User = get_user_model()
class UserAdmin(BaseUserAdmin):
# The forms to add and change user instances
form = UserAdminChangeForm
add_form = UserAdminCreationForm
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = ('email', 'admin')
list_filter = ('admin', 'staff', 'admin')
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ('first_name', 'last_name')}),
('Permissions', {'fields': ('admin', 'staff', 'active')}),
)
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'first_name', 'last_name', 'password1', 'password2')}
),
)
search_fields = ('email', 'first_name', 'last_name')
ordering = ('email',)
filter_horizontal = ()
admin.site.register(User, UserAdmin)
# Remove Group Model from admin. We're not using it.
admin.site.unregister(Group)
REQUIRED_FIELD should be REQUIRED_FIELDS
https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#django.contrib.auth.models.CustomUser.REQUIRED_FIELDS
create_superuser() missing 4 required positional arguments: 'name', 'birthday', 'phone', and 'gender'
have added REQUIRED_FIELDS in extended user model and It works.
'''
REQUIRED_FIELDS = ['name','birthday','phone','gender']
'''
class User(AbstractBaseUser):
.......
.......
REQUIRED_FIELDS = ['first_name', 'last_name']
.......
.......
Here, first_name and last_name is required means, when you try to create superuser, django ask for first and last name. look below for full code.
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(verbose_name='email address', max_length=255, unique=True, default=False, blank=False,
null=False)
first_name = models.CharField(max_length=200, blank=False)
last_name = models.CharField(max_length=200, blank=False)
date_joined = models.DateTimeField(default=datetime.now, blank=True)
is_active = models.BooleanField(default=True)
# a admin user; non super-user
is_staff = models.BooleanField(default=False)
# a superuser
is_superuser = models.BooleanField(default=False)
# notice the absence of a "Password fields", that is built in.
USERNAME_FIELD = 'email'
# Email and password are required by default
REQUIRED_FIELDS = ['first_name', 'last_name']
# this is UserManager objects that inherit user manager of django through above code
objects = UserManager()
# .create_superuser(email, first_name, last_name)
def get_full_name(self):
# The user is identified by their email address
return self.first_name, self.last_name
def get_first_name(self):
return self.first_name
def get_last_name(self):
return self.last_name
def get_email(self):
return self.email
def get_username(self):
return self.email
def __str__(self):
return self.email, self.first_name, self.last_name
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perm(self, app_label):
"Does the user have permission to view the app 'app_label'?"
# Simplest possible answer: Yes, always
return True
#property
def is_staffuser(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_superuser
#property
def user_status(self):
return self.is_active
In this code your username will be email, i replace username field with email so user can't use extra fields.