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)
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
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 Creating a Custom User using AbstractBaseUser, but anytime I try to create a superuser, it says
TypeError: User() got an unexpected keyword argument 'is_staff'
user=self._create_user(email, password, True, True, **extra_fields)
File "C:\Users\user1\django\customuserproject\users\models.py", line 24, in _create_user
How do I solve this problem? I have checked other StackOverflow posts on this issue, but they didn't help me. I haven't tried with a regular user yet (I need a superuser to create a regular user), but I am sure it would be the same thing
My models.py:
class UserManager(BaseUserManager):
def _create_user(self, email, password, is_staff, is_superuser, **extra_fields):
if not email:
raise ValueError('Users must have an email address')
now = timezone.now()
email = self.normalize_email(email)
user = self.model(
email=email,
is_staff=is_staff,
is_active=True,
is_superuser=is_superuser,
last_login=now,
date_joined=now,
**extra_fields
)
#user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password, **extra_fields):
"""
Creates and saves a User with the given email and password.
"""
return self._create_user(email, password, False, False, **extra_fields)
def create_staffuser(self, email, password, **extra_fields):
"""
Creates and saves a staff user with the given email and password.
"""
user=self._create_user(email, password, True, False, **extra_fields)
user.save(using=self._db)
return user
def create_superuser(self, email, password, **extra_fields):
"""
Creates and saves a superuser with the given email and password.
"""
user=self._create_user(email, password, True, True, **extra_fields)
user.save(using=self._db)
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
first_name = models.CharField(max_length=70, null=True, blank=True)
last_name = models.CharField(max_length=70, null=True, blank=True)
display_name = models.CharField(('display name'), max_length=70, blank=True, null=True, unique=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False) # a admin user; non super-user
is_superuser = models.BooleanField(default=False) # a superuser
last_login = models.DateTimeField(null=True, blank=True)
date_joined = models.DateTimeField(auto_now_add=True)
# notice the absence of a "Password field", that is built in.
objects = UserManager()
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name'] # Email & Password are required by default.
class Meta:
verbose_name = ('user')
verbose_name_plural = ('users')
#db_table = 'auth_user'
abstract = False
def get_absolute_url(self):
return "/users/%i/" % (self.pk)
#property
def name(self):
if self.first_name:
return self.first_name
elif self.display_name:
return self.display_name
return 'You'
def get_full_name(self):
"""
Return the first_name plus the last_name, with a space in between.
"""
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
return self.first_name
def email_user(self, subject, message, from_email=None):
send_mail(subject, message, from_email, [self.email])
def __str__(self):
return self.email
def natural_key(self):
return (self.email,)
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.is_staff
#property
def is_superuser(self):
return self.is_superuser
#property
def is_active(self):
return self.is_active
Try using getter and setters with #property they work a lot better and are clearly implemented.
class Demo:
def __init__(self):
self._age = 0
# using property decorator
# a getter function
#property
def age(self):
print("getter method called")
return self._age
# a setter function
#age.setter
def age(self, a):
if(a < 18):
raise ValueError("Sorry you age is below eligibility criteria")
print("setter method called")
self._age = a
 Â
Thanks #Iain Shelvington, #Willem Van Onsem, and #7u5h4r.
I solved the problem by removing all the properties I declared, while leaving only the variables: is_staff, is_superuser, is_active.
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']
)
I created a custom user model for my Django project so that the user could login in with their email. However, the authentication wouldn't work.
Here is my code:
Views:
def login_view(request):
if request.method == "POST":
form = LoginForm(request.POST)
if form.is_valid():
email = form.cleaned_data.get('email')
password = form.cleaned_data.get('password')
user = authenticate(usename=email, password=password)
if user:
print(True)
login(request, user)
return redirect('/account/')
else:
print(str(password)+" "+str(email))
print(False)
else:
form = LoginForm()
return render(request, 'users/login.html',{'form': form})
my backend:
def authenticate(self, username=None, password=None,):
try:
user = User.objects.get(email=username)
if user.check_password(password):
return True
except User.DoesNotExist:
return True
def get_user(self, user_id):
try:
user = User.objects.get(pk=user_id)
if user.is_active:
return user
return None
except User.DoesNotExist:
return None
My User Model:
class UserManager(BaseUserManager):
def _create_user(self, first_name, last_name, username, email, is_admin, password=None, **extra_fields):
"""
creates a User with first name, last name, username, email, password
"""
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
user = self.model(
first_name=first_name,
last_name=last_name,
username=username,
email=email,
is_admin=is_admin,
is_active=True,
**extra_fields,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, first_name, last_name, username, email, password, **extra_fields):
return self._create_user(
first_name,
last_name,
username,
email,
False,
password,
**extra_fields
)
def create_superuser(self, first_name, last_name, username, email, password=None, **extra_fields):
return self._create_user(
first_name,
last_name,
username,
email,
True,
password,
**extra_fields
)
class User(AbstractBaseUser):
first_name = models.CharField(
max_length=256,
unique=False,
verbose_name='first name',
)
last_name = models.CharField(
verbose_name='last name',
max_length=256,
unique=False,
)
username = models.CharField(
verbose_name='username',
max_length=256,
unique=False,
)
email = models.EmailField(
verbose_name='email',
max_length=256,
unique=True,
)
is_active = models.BooleanField(
default=True,
)
is_admin = models.BooleanField(
default=False,
)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = [
'first_name',
'last_name',
'username',
]
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def get_full_name(self):
full_name = "{} {}".format(self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
return self.first_name
def __str__(self): # __unicode__ on Python 2
return self.email
def email_user(self, subject, message, from_email):
send_mail(subject, message, from_email, [self.email])
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
def has_perm(self, perm, obj=None):
return self.is_admin
#property
def is_staff(self):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return self.is_admin
My settings:
AUTH_USER_MODEL = 'custom_user.User'
AUTHENTICATION_BACKENDS = ('custom_user.backends.UserAuth', )
My Forms:
email = forms.CharField(
widget=forms.TextInput(attrs={'class': 'registerforms', 'placeholder': 'Email'}),
label='',
)
password = forms.CharField(
widget=forms.PasswordInput(attrs={'class': 'registerforms', 'placeholder': 'Password'}),
label='',
)
I do not get an error however it doesn't log the user in