a pretty noob here. I am trying to create a user profile at the time when the account is created using signals. I want all the fields of the user profile to be filled in sign up page.
This is the user profile that I am trying to populate:
class UserProfile(models.Model):
user = models.ForeignKey(get_user_model(), verbose_name='user', on_delete=models.CASCADE)
name = models.CharField(max_length=255, null=True)
contact_number = models.CharField(max_length=11, default="0331232132")
def __str__(self):
return self.name
This is my custom user model here:
class CustomUserManager(BaseUserManager):
def _create_user(self, email, password, **kwargs):
if not email:
raise ValueError("The given email must be set")
email = self.normalize_email(email)
user = self.model(email=email, **kwargs)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **kwargs):
kwargs.setdefault("is_staff", False)
kwargs.setdefault("is_superuser", False)
return self._create_user(email, password, **kwargs)
def create_superuser(self, email, password=None, **kwargs):
kwargs.setdefault("is_staff", True)
kwargs.setdefault("is_superuser", True)
if kwargs.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if kwargs.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self._create_user(email, password, **kwargs)
class User(AbstractUser):
username = None
email = models.EmailField(_("email address"), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
This is my user creation form that I am sending to template:
class CustomUserCreationForm(UserCreationForm):
password2 = forms.CharField(
label=_("Confirm Password"),
widget=forms.PasswordInput,
)
name = forms.CharField()
contact_number = forms.CharField(
max_length=11
)
class Meta:
model = get_user_model()
fields = ['email']
I am not sure if it is relevant but this is my custom email backend.
class EmailBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try:
user = User.objects.get(email__iexact=username)
except User.DoesNotExist:
return None
except User.MultipleObjectsReturned:
return User.objects.filter(email=username).order_by('id').first()
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
def get_user(self, user_id):
try:
user = User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
return user if self.user_can_authenticate(user) else None
Now what I want is when the user submits the user creation form, Email and Password field is used to create a user account while name and contact number along with the newly created user object are used to create a userprofile instance using signals. All the examples that I have seen till now only handle setting only the user object in profile.
Related
I'm trying to create a user from the Django rest framework's ModelViewset. (However, I've also tried to do the same with regular Django's model form. In both cases, the CustomUser model is not using the create_user function from the Model manager.
My codes are as follows:
Model Manager
class CustomUserManager(BaseUserManager):
def create_user(self, email, phone, full_name, **other_fields):
email = self.normalize_email(email)
if not email:
raise ValueError("User must have an email")
if not full_name:
raise ValueError("User must have a full name")
if not phone:
raise ValueError("User must have a phone number")
user = self.model(
email=self.normalize_email(email),
phone=phone,
full_name=full_name,
is_active=True,
)
other_fields.setdefault('is_active', True)
user.set_password(phone)
user.save(using=self._db)
return user
def create_superuser(self, email, phone, full_name, password=None, **other_fields):
if not email:
raise ValueError("User must have an email")
if not password:
raise ValueError("User must have a password")
if not full_name:
raise ValueError("User must have a full name")
if not phone:
raise ValueError("User must have a phone number")
user = self.model(
email=self.normalize_email(email),
full_name = full_name,
phone = phone
)
user.set_password(password) # change password to hash
other_fields.setdefault('is_staff', True)
other_fields.setdefault('is_superuser', True)
other_fields.setdefault('is_active', True)
user.save(using=self._db)
return user
Model:
class CustomUserModel(AbstractBaseUser, PermissionsMixin, AbstractModel):
email = models.EmailField(unique=True)
username = models.CharField( max_length=150, unique=True, null=True, blank=True)
phone = PhoneNumberField(unique=True)
full_name = models.CharField(max_length=50, null=True, blank=True)
is_active = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
objects = CustomUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['phone', 'full_name']
class Meta:
verbose_name = 'User'
verbose_name_plural = 'Users'
def __str__(self):
return f'{self.username} - {self.email}'
def save(self, *args, **kwargs):
if not self.username:
uid = str(uuid4()).split('-')[1].upper()
today = str(date.today()).replace('-', '').swapcase()
splitted_uname = self.full_name.split(' ')[0][:2].upper()
self.username = f'{splitted_uname}-{uid}{today}'
super(CustomUserModel, self).save(*args, **kwargs)
Django REST Framework's ViewSet
class UserBaseViewSet(viewsets.ModelViewSet):
allowed_methods = ('GET', 'POST', 'PATCH')
serializer_class = serializers.UserBaseListSerializer
queryset = CustomUserModel.objects.all()
permission_classes = [IsProfileOwnerOrReadOnly, ]
lookup_field = 'username'
def get_serializer_class(self):
if self.action == 'retrieve':
return serializers.UserBaseDetailSerializer
return super().get_serializer_class()
While creating superusers from the command line it works perfectly.
What am I missing in this process?
I debug the process but the model class doesn't users the create_user function of the manager in any way.
You will have to override create of UserBaseListSerializer to call the manager's create_user:
class UserBaseListSerializer(serializers.ModelSerializer):
...
def create(self, validated_data):
return CustomUserModel.objects.create_user(**validated_data)
when i am sending post request to register new user from postman, username saves as blank/dash .
why username saving as blank i dont get it.
but when i add from django admin it saves correctly.
here is postman image
postman post request image
and here is the result
django result after sending post request
Custom Account Manager
class CustomAccountManager(BaseUserManager):
def create_superuser(self, email, username, password, **other_fields):
other_fields.setdefault('is_staff', True)
other_fields.setdefault('is_active', True)
other_fields.setdefault('is_admin', True)
other_fields.setdefault('is_superuser', True)
if other_fields.get('is_staff') is not True:
raise ValueError(
'Superuser must be assigned to is_staff=True.')
if other_fields.get('is_superuser') is not True:
raise ValueError(
'Superuser must be assigned to is_superuser=True.')
return self.create_user(email, username, password, **other_fields)
def create_user(self, email, username, password, **other_fields):
if not email:
raise ValueError(_('You must provide an email address'))
if not username:
raise ValueError(_('You must provide an username'))
if " " in username:
raise ValueError(_('Username should not contain space'))
email = self.normalize_email(email)
user = self.model(email=email, username=username, **other_fields)
user.set_password(password)
user.save()
return user
Custom User Model
class NewUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True, null=False, blank=False)
username = models.CharField(max_length=150, unique=True, null=True)
first_name = models.CharField(max_length=150, blank=True)
objects = CustomAccountManager()
# more
class Meta:
verbose_name = 'NewUser'
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
def __str__(self):
return str(self.username)
model serializer
class RegisterNewUserSerializer(serializers.ModelSerializer):
class Meta:
model = NewUser
fields = ('email', 'password', 'username')
extra_kwargs={'password':{'write_only':True}}
def validate(self, data):
if hasattr(self, 'initial_data'):
unknown_keys = set(self.initial_data.keys()) - set(self.fields.keys())
if unknown_keys:
raise ValidationError("Got unknown fields: {}".format(unknown_keys))
return data
def validate_username(self, value):
if " " in value:
raise serializers.ValidationError("Username should not contain space")
def save(self):
newuser = NewUser(email = self.validated_data['email'],
username = self.validated_data['username']
)
password = self.validated_data['password']
newuser.set_password(password)
newuser.save()
return newuser
post request
class RegistrationView(APIView):
permission_classes = [ AllowAny ]
def post(self, request):
reg_serializer = RegisterNewUserSerializer(data = request.data)
print(request.data)
print(reg_serializer)
if reg_serializer.is_valid():
print('lololololololololololo')
reg_serializer.save()
return Response(data=request.data,status=status.HTTP_201_CREATED)
return Response(reg_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
You validator should return the data, so:
def validate_username(self, value):
if " " in value:
raise serializers.ValidationError("Username should not contain space")
# ↓ return the value
return value
In Python a function call always returns something (unless an exception is raised). If no explicit return statement is triggered, None is returned.
I created a register/login system through DRF by overriding dj_rest_auth
If registering an user with Postman, by firing on the endpoint, that user can be used for login through endpoint
However, if creating an user through Django Admin, that user cannot be used for login through endpoint, and notably, if seen through Django Admin, the password is not hashed
How to handle this?
serializers.py
class CustomLoginSerializer(LoginSerializer):
def validate_auth_user_status(self, user):
request = self.context.get('request')
if not request.data.get('role'):
msg = 'Role is missing from the payload.'
raise exceptions.ValidationError(msg)
if not user.groups.filter(name=request.data.get('role')).exists():
msg = 'Invalid role for the user.'
raise exceptions.ValidationError(msg)
def create(self, validated_data):
pass # Empty because the function is not needed
# but Pylint demanded to implement it anyway
def update(self, instance, validated_data):
pass # Empty because the function is not needed
# but Pylint demanded to implement it anyway
class CustomRegisterSerializer(RegisterSerializer):
name = serializers.CharField()
def get_cleaned_data(self):
super().get_cleaned_data()
return {
'email': self.validated_data.get('email', ''),
'password1': self.validated_data.get('password1', ''),
'name': self.validated_data.get('name', '')
}
def create(self, validated_data):
pass # Empty because the function is not needed
# but Pylint demanded to implement it anyway
def update(self, instance, validated_data):
pass # Empty because the function is not needed
# but Pylint demanded to implement it anyway
def save(self, request):
user = super().save(request)
user.name = self.get_cleaned_data().get('name')
user.save()
client_role, _created = Group.objects.get_or_create(name='client')
user.groups.add(client_role)
return user
urls.py
urlpatterns = [
path('auth/registration/', include('dj_rest_auth.registration.urls')),
path('auth/', include('dj_rest_auth.urls')),
path('auth/user-login/', CustomLoginView.as_view(), name='custom_user_login'),
path('auth/google/', GoogleView.as_view(), name='google'),
]
models.py
class CustomUser(AbstractBaseUser, PermissionsMixin):
name = models.CharField(max_length=100)
email = models.EmailField(_('email address'), unique=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
diet_profile = models.OneToOneField(
DietProfile,
on_delete=models.CASCADE,
primary_key=False,
related_name="user",
blank=True, null=True
)
nutritionist = models.ForeignKey(
Nutritionist,
on_delete=models.CASCADE,
related_name="clients",
blank=True,
null=True
)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return str(self.email)
EDIT:
adding custom user manager and admin.py
manager.py
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()
client_role, _created = Group.objects.get_or_create(name='client')
user.groups.add(client_role)
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)
admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import CustomUser
admin.site.register(CustomUser)
When I call the api/seller/register api, the fields appear are username, password1 and password2. I want these removed and only want simple password, email and phone_num.
How to remove this?
I am trying to make a seller registration using RegisterSerializer. I tried with ModelSerailzers and provided fields as I want but this will lead to me the error saying save() only takes 1 argument.So, I just want these unnecessary fields removed using RegisterSerializer.
My model:
class CustomUserManager(BaseUserManager):
"""
Custom user model manager with email as the unique identifier
"""
def create_user(self, first_name, last_name, email, password, **extra_fields):
"""
Create user with the given email and password.
"""
if not email:
raise ValueError("The email must be set")
first_name = first_name.capitalize()
last_name = last_name.capitalize()
email = self.normalize_email(email)
user = self.model(
first_name=first_name, last_name=last_name, email=email, **extra_fields
)
user.set_password(password)
user.save()
return user
def create_superuser(self, first_name, last_name, email, password, **extra_fields):
"""
Create 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(first_name, last_name, email, password, **extra_fields)
class CustomUser(AbstractUser):
username = models.CharField(max_length=255,blank=False)
first_name = models.CharField(max_length=255, verbose_name="First name")
last_name = models.CharField(max_length=255, verbose_name="Last name")
email = models.EmailField(unique=True)
is_seller = models.BooleanField(default=False)
is_customer = models.BooleanField(default=False)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["first_name", "last_name"]
objects = CustomUserManager()
def __str__(self):
return self.email
My serializer:
class SellerRegisterSerializer(RegisterSerializer):
seller = serializers.PrimaryKeyRelatedField(read_only=True,)
# username = serializers.CharField(required=True)
phone_num = serializers.CharField(required=False)
# class Meta:
# model = User
# fields = ['seller','email', 'phone_num', 'first_name', 'last_name', 'password']
def get_cleaned_data(self):
data = super(SellerRegisterSerializer, self).get_cleaned_data()
extra_data = {
'phone_num': self.validated_data.get('phone_num', ''),
}
data.update(extra_data)
return data
def save(self, request, **kwargs):
user = super(SellerRegisterSerializer, self).save(request)
# user = super().save(is_seller=True)
user.is_seller = True
user.save()
seller = Seller(seller=user,
phone_num=self.cleaned_data.get('phone_num'))
seller.save()
return user
My view:
class SellerRegisterView(RegisterView):
serializer_class = SellerRegisterSerializer
So I'm making a custom user model. This is what I'am following Here. I have been pretty much following the tutorial but still I cant make it done.
Error: RegisterForm() missing 1 required positional argument: 'request'.
here's my code.
forms.py
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from .models import User
class UserAdminCreationForm(forms.ModelForm):
"""
A form for creating new users. Includes all the required
fields, plus a repeated password.
"""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email',)
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserAdminChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = User
fields = ('email', 'password', 'active', 'admin')
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
class LoginForm(forms.ModelForm):
email = forms.EmailField(label='Email')
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email', 'password',)
widgets = {
'email' : forms.EmailInput(
attrs={'class':'form-control', 'place_holder': '', }),
'password' : forms.PasswordInput(
attrs={'class':'form-control' }),
}
class RegisterForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email',)
def clean_email(self):
email = self.cleaned_data.get('email')
qs = User.objects.filter(email=email)
if qs.exists():
raise forms.ValidationError("email is taken")
return email
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
models.py
from django.db import models
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser
)
class UserManager(BaseUserManager):
def create_user(self, email, full_name, password=None, is_staff=False, is_active=True, is_admin=False):
"""
Creates and saves a User with the given email and password.
"""
if not email:
raise ValueError('Users must have an email address')
if not full_name:
raise ValueError('Users must have an full name')
if not password:
raise ValueError('Users must have a password')
user = self.model(
email=self.normalize_email(email),
)
user.full_name = full_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, password):
"""
Creates and saves a staff user with the given email and password.
"""
user = self.create_user(
email,
password=password,
)
user.staff = True
user.save(using=self._db)
return user
def create_superuser(self, email, full_name, password):
"""
Creates and saves a superuser with the given email and password.
"""
user = self.model(
email=self.normalize_email(email)
)
user.full_name = full_name
user.set_password(password)
user.full_name = full_name
user.staff = True
user.admin = True
user.save(using=self._db)
return user
# Create your models here.
class User(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True)
full_name = models.CharField(max_length=255, null=True, blank=True)
active = models.BooleanField(default=True) # to login
staff = models.BooleanField(default=False) # a admin user; non super-user
admin = models.BooleanField(default=False) # a superuser
created_date = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['full_name'] # Email & Password are required by default.
objects = UserManager()
def __str__(self):
return self.email
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 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.staff
#property
def is_admin(self):
"Is the user a admin member?"
return self.admin
#property
def is_active(self):
"Is the user active?"
return self.active
class Account_type(models.Model):
name = models.CharField(max_length=50, null=True, blank=True)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
account_type = models.ForeignKey(Account_type, on_delete=models.CASCADE)
register.html
from django.shortcuts import render, redirect
from . forms import RegisterForm, LoginForm
# Create your views here.
def RegisterForm(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
else:
form = RegisterForm()
context = {
'form' : form
}
return render(request, 'account/register.html', context)
The view logic is simple as you can see. Just saving up the request into the database. The tutorial itself did not tell anything about the view for login and register.
So, What am I doing wrong here.
Thank you
The problem is that your view RegisterForm has the same name as your form, hence if you call RegisterForm in your view, it will resolve to the view function, and make a recursive call.
Normally (top-level) functions are written in snake_case, hence you can rewrite it to register_form, or even better register (since it is not a form at all):
from django.shortcuts import render, redirect
from . forms import RegisterForm, LoginForm
# Create your views here.
def register(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
return redirect('some-view-name')
else:
form = RegisterForm()
context = {
'form' : form
}
return render(request, 'account/register.html', context)
Normally a successful POST request results in a redirect to implement the Post/Redirect/Get pattern [wiki]. So I strongly advise you to use redirect(..) [Django-doc] and replace some-view-name with the name of a view to which you want to redirect.