I have a base User model and two other models Candidate and Company
User:
email
password
is_company => default=False
Form class:
class CustomUserCreationForm(forms.Form):
email = forms.EmailField(label='Enter email', widget=forms.EmailInput(attrs={'placeholder': 'Email Address', 'spellcheck':'False', 'autofocus':'True'}))
password = forms.CharField(label='Enter password', min_length=8, widget=forms.PasswordInput(attrs={'placeholder': 'Password'}))
def clean_email(self):
email = self.cleaned_data['email'].lower()
r = User.objects.filter(email=email)
if r.count():
raise ValidationError("Email already exists")
return email
def clean_password(self):
password = self.cleaned_data.get('password')
return password
def save(self, commit=True):
user = User.objects.create_user(
self.cleaned_data['email'],
self.cleaned_data['password']
)
return user
My UserManager:
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
"""
Creates and saves a User with the given email and password.
"""
try:
validate_email(email)
valid_email = True
except ValidationError:
valid_email = False
if not valid_email:
raise ValueError('Valid Email is required')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
subject = 'Activate Your Account'
message = render_to_string('registration/account_activation_email.html', {
'domain': 'example.in',
'user': user,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
user.email_user(subject, 'example <admin#example.in>', html_message=message)
return user
def create_user(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_superuser', False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_superuser', 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)
In my user creation view:
class SignUpView(View):
is_company = False
def get(self, request):
if request.user.is_authenticated():
return redirect(reverse_lazy('dashboard'))
form = CustomUserCreationForm()
return render(request, 'registration/signup.html', {'form': form, 'is_company':self.is_company})
def post(self,request):
form = CustomUserCreationForm(request.POST or None, request.FILES or None)
if form.is_valid():
user = form.save(commit=False)
user.is_active = False
user.is_company = self.is_company
user.save()
return render(request, 'registration/account_activation_sent.html')
return render(request, 'registration/signup.html', {'form': form, 'is_company':self.is_company})
I have created a post_save signal for the above model.
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
if instance.is_company:
Company.objects.create(user=instance)
instance.company.save()
else:
Candidate.objects.create(user=instance,
first_name=instance.is_company )
instance.candidate.save()
urls.py:
url(r'^accounts/signup/company/',vw.SignUpView.as_view(is_company = True), name='signup_company')
The problem is the form.save(commit=False) is triggering the post_save signal. I end up having instance.is_company as False, thus creating a CandidateProfile for a Company.
But the the database user table is populated with is_company as True for the company.
Please help!
You should try disconnecting the post_save signal before working on your instance and connecting it later.
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
# disconnect post_save
post_save.disconnect(update_user_profile, sender=sender)
# do something with your instance
# connect post_save
post_save.connect(update_user_profile, sender=sender)
In your form you have overridden save and are always calling create_user which will call user.save(using=self._db) i.e not passing the value of commit
What you can do is override _create_user in your User model to pass the value of commit to it
class User(AbstractBaseUser):
...
def _create_user(self, username, email, password, commit=True, **extra_fields):
if not username:
raise ValueError('The given username 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)
if commit:
user.save(using=self._db)
return user
And then in your form you can pass the value of commit to it
class CustomUserCreationForm(forms.Form):
def save(self, commit=True):
return User.objects.create_user(
self.cleaned_data['email'],
self.cleaned_data['password'],
commit=False
)
Edit: Looking into this code again, I feel it is bad.
You're better off fixing your logic in the form to do multiple saves
class CustomUserCreationForm(forms.Form):
def save(self, commit=True):
is_create = self.instance.pk is None
user = super().save(commit=commit)
user.set_password(self.cleaned_data['password'])
user.save()
if not is_create:
return user
if user.is_company:
Company.objects.create(user=user)
user.company.save() # not really needed
else:
Candidate.objects.create(user=user, first_name=user.is_company)
user.candidate.save() # not really needed
return user
P.S: I personally dislike django signal as they can cause confusion as to what is happening. It might be better to do this in your view or in the form save instead. You should have only one way of creating new users so it shouldn't be a big problem.
Change your argument to default False and check if this is true before saving... with your way doenst matter if you call it with commit false or true, they will always save in data base... so because of that they are triggers your post_save
def save(self, commit=False):
if commit:
user = User.objects.create_user(
self.cleaned_data['email'],
self.cleaned_data['password']
)
Related
I am writing a test for my views to check if the POST data is validated but the test failed with this error,
self.assertTrue(form.is_valid())
AssertionError: False is not true
Am thinking the error might be coming from the form validity.
Below are my codes
tests.py
class CreateAccountTest(TestCase):
email = "example#gmail.com"
def test_signup_page_status_code(self):
response = self.client.get('/accounts/signup/')
self.assertEqual(response.status_code, 200)
def test_signup_url_by_name_and_uses_correct_template(self):
response = self.client.get(reverse ('register'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'registration/signup.html')
def test_signup_empty_form(self):
form = CustomUserCreationForm()
self.assertIn('first_name', form.fields)
self.assertIn('last_name', form.fields)
self.assertIn('password1', form.fields)
self.assertIn('password2', form.fields)
def test_signup__post_form(self):
request = HttpRequest()
request.POST = {
'email': self.email,
'first_name': 'Adam',
'last_name': 'Smith',
'password1': 'qazxswedcvfr',
'password2': 'qazxswedcvfr',
}
form = CustomUserCreationForm(request.POST)
self.assertTrue(form.is_valid())
form.save()
self.assertEqual(get_user_model().objects.all().count(), 1)
This is My CustomUser model
class CustomUserManager(BaseUserManager):
"""
Custom user model manger where email is the unique identifiers for authentication rather than username
"""
def create_user(self, email, password, **extra_fields):
'''
Create and save a user with the given email and password
'''
if not email:
raise ValueError(_('Email must be set'))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
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)
This is the models.py for the Customusermanager
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
Trying to store the pw hashed works but trying to login with the first_name + last_name doesn't work. Etc if the combined pw is named ThisPw I should be able to store it hashed and then login with it.
if add_form.is_valid():
post = request.POST
print(post['email'])
new_password = post['first_name']+post['last_name']
new_user = Profile.objects.create_user(
email = post['email'],
password=make_password(new_password),
first_name=post['first_name'],
last_name=post['last_name'],
phone_number=post['phone_number'],
)
print(new_password)
new_user.save()
print(add_form)
return redirect('add')
Do not use make_password() if you are passing the password to the default create_user() method.
if add_form.is_valid():
post = request.POST
new_password = post['first_name']+post['last_name']
new_user = Profile.objects.create_user(
email = post['email'],
password=new_password,
first_name=post['first_name'],
last_name=post['last_name'],
phone_number=post['phone_number'],
)
new_user.save()
return redirect('add')
The default create_user() method is calling user.set_password(password)
class UserManager(BaseUserManager):
def _create_user(self, username, email, password, **extra_fields):
"""
Create and save a user with the given username, email, and password.
"""
# ...
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, username, email=None, password=None, **extra_fields):
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
return self._create_user(username, email, password, **extra_fields)
class AbstractBaseUser(models.Model):
# Stores the raw password if set_password() is called so that it can
# be passed to password_changed() after the model is saved.
_password = None
def set_password(self, raw_password):
self.password = make_password(raw_password)
self._password = raw_password
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'm trying to create superusers on the django admin backend, but somehow I can't get them to log in.
Here's my user class,
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, max_length=255)
mobile = PhoneNumberField(null=True)
username = models.CharField(null=False, unique=True, max_length=255)
full_name = models.CharField(max_length=255, blank=True, null=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = UserManager()
Here's the UserManager function to create super user,
class UserManager(BaseUserManager):
def create_user(self, email, mobile=None, username=None, full_name=None, gender=None, birthday=None, password=None,
is_staff=False,
is_superuser=False, is_active=False, is_mobile_verified=False, is_bot=False, is_online=False,
is_logged_in=True):
if not email:
raise ValueError("Can't create User without a mobile number!")
if not password:
raise ValueError("Can't create User without a password!")
user = self.model(
email=self.normalize_email(email),
mobile=mobile,
username=username,
full_name=full_name,
gender=gender,
birthday=birthday,
is_staff=is_staff,
is_superuser=is_superuser,
is_active=is_active,
)
user.set_password(password)
return user
def create_superuser(self, email, username, password=None):
user = self.create_user(
email,
username=username,
password=password,
is_staff=True,
is_superuser=True,
is_active=True,
)
user.save(self._db)
return user
#property
def is_superuser(self):
return self.is_superuser
#property
def is_staff(self):
return self.is_staff
#property
def is_active(self):
return self.is_active
#property
def is_mobile_verified(self):
return self.is_mobile_verified
def has_perm(self, perm, obj=None):
return self.is_staff or self.is_superuser
def has_module_perms(self, app_label):
return self.is_staff or self.is_superuser
#is_staff.setter
def is_staff(self, value):
self._is_staff = value
#is_superuser.setter
def is_superuser(self, value):
self._is_superuser = value
#is_active.setter
def is_active(self, value):
self._is_active = value
Here's the relevant backend settings.
OAUTH2_PROVIDER = {
# this is the list of available scopes
'ACCESS_TOKEN_EXPIRE_SECONDS': 60 * 60 * 24,
'SCOPES': {'read': 'Read scope', 'write': 'Write scope', 'groups': 'Access to your groups'},
'OAUTH2_BACKEND_CLASS': 'oauth2_provider.oauth2_backends.JSONOAuthLibCore',
}
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
)
# REST Framework
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
}
I'm checking the is_staff and is_superuser to true on the creation form, still nothing. The created super user can't log in on the admin backend.
What am I doing wrong here.
First,
you are using custom user model. In your settings file, do you tell django to use your model instead of default auth.models.User ?
Second,
you are calling self.create_user inside your create_superuser function.
Do you override the create_user function as well ?
If yes, please provide the implementation.
Update
You dont need to change implementation user mansger's functions as you did.
IF you look at implementation of UserManger in django.auth.models. You can take inspiration from there and you avoid making a mistake - for example: you dont save model when you create standard user as you dont call save method.
I suggest to change your UserManager like this:
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password,
**extra_fields):
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
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('is_active', False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, 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, password, **extra_fields)
I created a new project with your code and I cannot reproduce your problem. Everything works fine on my side. However, I do notice a few things about your code:
First, in your settings.py, make sure you have set AUTH_USER_MODEL to your_app.User.
Second, in your UserManager class, I found things this:
#property
def is_staff(self):
return self.is_staff
This looks like an error to me, as it would produces infinite recursions. I guess in your case, there is a catch-all clause in django's code so the RecursionError is silenced. This may very likely be the problem.
i tried create_user for email login as custom user model, but it's not working.
save() missing 1 required positional argument 'request'.
how can i solve this problem, help me please.
this is Traceback..
File "/Users/maxx/.local/share/virtualenvs/testauth--sM0sqjl/lib/python3.6/site-packages/rest_framework/views.py", line 480, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/maxx/Documents/workspace/python3/testauth/users/views.py", line 12, in post
user = serializer.save()
TypeError: save() missing 1 required positional argument: 'request'
models.py
class UserManger(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
if not email:
raise ValueError('You must give email address')
email = self.normalize_email(email)
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, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
return self._create_user(email, password, **extra_fields)
class User(AbstractBaseUser):
email = models.EmailField(unique=True)
nick_name = models.CharField(max_length=50)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManger()
def __str__(self):
return self.email
def get_full_name(self):
return self.email
def get_short_name(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
serializers.py
class RegisterSerializer(serializers.Serializer):
email = serializers.EmailField(required=allauth_settings.EMAIL_REQUIRED)
password1 = serializers.CharField(write_only=True)
password2 = serializers.CharField(write_only=True)
def validate_email(self, email):
email = get_adapter().clean_email(email)
if allauth_settings.UNIQUE_EMAIL:
if email and email_address_exists(email):
raise serializers.ValidationError(
_("A user is already registered with this e-mail address."))
return email
def validate_password1(self, password):
return get_adapter().clean_password(password)
def validate(self, data):
if data['password1'] != data['password2']:
raise serializers.ValidationError(_("password fields didn't match."))
return data
def get_cleaned_data(self):
return {
'email': self.validated_data.get('email', ''),
'password1': self.validated_data.get('password1', ''),
}
def save(self, request):
adapter = get_adapter()
user = adapter.new_user(request)
self.cleaned_data = self.get_cleaned_data()
adapter.save_user(request, user, self)
setup_user_email(request, user, [])
return user
views.py
class UserCreateView(APIView):
def post(self, request):
serializer = RegisterSerializer(data=request.data)
if serializer.is_valid():
user = serializer.save()
if user:
token = Token.objects.create(user=user)
json = serializer.data
json['token'] = token.key
return Response(json, status=status.HTTP_201_CREATED)
return Response(data=serializer.errors ,status=status.HTTP_400_BAD_REQUEST)
In your RegisterSerializer you have implemented a save() method that requires a positional argument named request, in UserCreateView you need to include the request in that method call.
class UserCreateView(APIView):
def post(self, request):
serializer = RegisterSerializer(data=request.data)
if serializer.is_valid():
user = serializer.save(request) # <---- INCLUDE REQUEST
if user:
token = Token.objects.create(user=user)
json = serializer.data
json['token'] = token.key
return Response(json, status=status.HTTP_201_CREATED)
return Response(data=serializer.errors ,status=status.HTTP_400_BAD_REQUEST)