Change Django Authentication Model password field - python

I am trying to modify my Django project authentication so I can use my own User model.
I have got it working so far, however I am unable to override the "password" field. I want to change the name to "password_hash".
I have tried this manager:
class UserManager(BaseUserManager):
def create_user(self, email_address, full_name, password=None):
if not email_address:
raise ValueError('Users must have an email address')
user = self.model(
email_address = self.normalize_email(email_address),
full_name = full_name,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email_address, full_name, password_hash):
user = self.create_user(email_address,
password_hash=password_hash,
full_name=full_name,
)
user.is_admin = True
user.save(using=self._db)
return user
However I get the error TypeError: create_superuser() got an unexpected keyword argument 'password'.
How do I stop create_superuser() from expecting "password" and change it to "password_hash". For username I did it by changing the USERNAME_FIELD, however nothing in the documentation suggests a similar method for the password.
Thanks in advance,
Mark

The solution that worked for me was to override this method in my new user model:
def set_password(self, raw_password):
self.password = make_password(raw_password)

Related

Django/Python: post_save signal - expected string or bytes-like object

I have a post_save signal which is failing with 'expected string or bytes-like object'. I am not sure why, it is being caused by the call to create_user below:-
This is to create a user within a tenant schema for a newly created tenant:
#receiver(post_save, sender=Client)
def create_user(sender, instance, created, **kwargs):
if created:
tenant=instance
with schema_context(tenant):
name = 'name'
email = 'name#email.com'
password = 'passwordexample'
user = CustomUser.objects.create_user(name, email, password)
The underlying user manager which throws the exception is
def create_user(self, name, 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'))
name = self.normalize_email(name)
email = self.normalize_email(email)
user = self.model(name=name, email=email, **extra_fields)
user.set_password(password)
user.save()
return user
This seems to fail on user.save() in the above manager
Any help or pointers greatly appreciated
Thank you
I think the problem you are facing not in Custom user manager it is in
with schema_context(tenant)
as this schema_context takes schema name not tenant
so I think you need to pass schema_name
or if you know tenants use
the following instead
from django_tenants.utils import tenant_context
with tenant_context(tenant):
# All commands here are ran under the schema from the `tenant` object

I don't understand how creating a custom user works

I'm reading the Django 3.2 documentation (custom authentication) and there are some lines of code that I can't understand.
I will try to read and explain what I can understand, or what I think I understand. Please correct me if I am wrong
Resource link: https://docs.djangoproject.com/es/3.2/topics/auth/customizing/
Code:
from django.db import models
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser
)
class MyUserManager(BaseUserManager):
def create_user(self, email, date_of_birth, password=None):
"""
Creates and saves a User with the given email, date of
birth and password.
"""
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
date_of_birth=date_of_birth,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, date_of_birth, password=None):
"""
Creates and saves a superuser with the given email, date of
birth and password.
"""
user = self.create_user(
email,
password=password,
date_of_birth=date_of_birth,
)
user.is_admin = True
user.save(using=self._db)
return user
class MyUser(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
date_of_birth = models.DateField()
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['date_of_birth']
def __str__(self):
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?"
# Simplest possible answer: All admins are staff
return self.is_admin
This method is used to create a standard user, it receives 2 main parameters: email and password.
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
If the field is not of the email type, execute error:
if not email:
raise ValueError("Users must have an email address")
I dont understand; I know that the normalize_email method puts all text in lowercase. But I don't understand the self.model (): this is not a method, is it? Shouldn't it be like this: user.email = self.normalize_email (email)?
user = self.model(
email=self.normalize_email(email),
)
The set_password method takes as an argument 'password' that the user entered, encrypts it and stores it in a structure or instance called user.
user.set_password(password)
The "save" method stores the record we have entered in the database. I have no idea how using = self._db works. Wouldn't it be enough to just call the save method? example user.save()
user.save(using=self._db)
create_superuser
This method creates an Admin, receives an email and a password. But I don't understand why you are referring to the create_user method.
user = self.create_user(...)
There is a line of code in the model that I don't understand its functionality either. Why instantiate the MyUserManager class in a variable called objects?
objects = MyUserManager()
Please explain me in an easy way

ValueError at /register/ Users must have an email address

This is my code in views.py
if form.is_valid():
print(form.cleaned_data)
username = form.cleaned_data.get("username")
email = form.cleaned_data.get("email")
password = form.cleaned_data.get("password")
new_user = User.objects.create_user(username, email, password)
Here is what is printed from the line 'print(form.cleaned_data)'
{'full_name': 'Ross', 'email': 'tree34-5#hotmail.com', 'profilepicture': None, 'password1': 'tree', 'password2': 'tree'}
Here is my code from models.py
class UserManager(BaseUserManager):
def create_user(self, email, full_name=None, password=None, is_active=True, is_staff=False, is_admin=False):
print(email)
if not email:
raise ValueError("Users must have an email address")
'print(email)' returns None. I don't understand why 'print(email)' is not returning tree34-5#hotmail.com. I keep getting the error message "Users must have an email address".
Based on this:
def create_user(self, email, full_name=None, password=None, is_active=True, is_staff=False, is_admin=False):
the first parameter you pass in should be email. But based on your code:
new_user = User.objects.create_user(username, email, password)
you are passing in a "username" instead of an email. That's the major problem.
You might consider to use "form.save()" instead of calling a method.
Your form.cleaned_data does not contain a username field hence None is returned with
form.cleaned_data.get("username")
You then set your email field to the username value as you have e-mail as a positional argument and passed in username as the first argument in this line
new_user = User.objects.create_user(username, email, password)
Change that line to the one below, this should get you what you want. It will unpack the dictionary into the arguments in the function automatically.
new_user = User.objects.create_user(**form.cleaned_data)
Adding to Wind's answer: if you insist on using User.objects.create_user(username, email, password), you must change your create_user to this:
def create_user(self, full_name=None, email, password=None, ...):
The reason why is that Django's create_user does not provide keyword arguments and therefore you must place everything in order. You need to swap the arguments "username" and "email" instead of simply replacing it otherwise the "password" parameter wouldn't work also.
Reference

django authenticate returning Nonetype with valid credentials

I have a custom user model based off of AbstractUser and, I use a custom UserManager, I don't know if theres anything special I have to do to get authenticate to work. I know the user is in the db because I can do objects.get(username, password) and it will return the object.
class PassThroughFarmerManager(PassThroughManagerMixin, UserManager):
use_in_migrations = False
class Farmer(FarmStateble, MapPointable, LastRequestStorable, AbstractUser):
last_irrigation_cycle = models.DateTimeField(auto_now_add=False, auto_now=False, null = True, blank=True)
objects = PassThroughFarmerManager.for_queryset_class(FarmerQuerySet)()
Here is an example of my console output,
>>> models.Farmer.objects.get(username='901e2ac5-9324-11e5-81bf-c42c0323e33a').password
u'1223'
>>> u = authenticate(username = '901e2ac5-9324-11e5-81bf-c42c0323e33a', password = '1223')
>>> u
>>> type(u)
<type 'NoneType'>
When you use MyUserModel.objects.create(...), the password is stored in the database in plain text. The call to authenticate does not work, because Django expects the password to be hashed in the database.
Therefore, when you create a user, you need to ensure that the password is hashed, rather than being stored in plain text in the database. You can do this by calling user.set_password('new_password').
The full example in the docs shows a create_user manager method that calls set_password when creating the user. You would then use MyUserModel.objects.create_user(...) instead of MyUserModel.objects.create(...).
class MyUserManager(BaseUserManager):
def create_user(self, email, date_of_birth, password=None):
"""
Creates and saves a User with the given email, date of
birth and password.
"""
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
date_of_birth=date_of_birth,
)
user.set_password(password)
user.save(using=self._db)
return user

Issues with username field in Python-social-auth

I am using Python socia auth for face-book. I have modified default Django behavior of User Model and removed username field .
I have added this in custom user model : USERNAME_FIELD = 'email'
BUt I am getting this error when trying to login
TypeError at /complete/facebook/
'username' is an invalid keyword argument for this function
I know when it is trying to create user it doesn't find username field and this throwing this error.
I have defined below settings but still my issue remains as it is :
SOCIAL_AUTH_USER_MODEL = 'accounts.User'
SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL = True
Any solution for this ?
I know it's few months since the question was posted, but I hit the same problem and found the solution.
This problem can be solved using pipeline. The default pipeline does this:
def create_user(strategy, details, user=None, *args, **kwargs):
if user:
return {'is_new': False}
fields = dict((name, kwargs.get(name) or details.get(name))
for name in strategy.setting('USER_FIELDS',
USER_FIELDS))
if not fields:
return
return {
'is_new': True,
'user': strategy.create_user(**fields)
}
Override USER_FIELDS in your settings end leave only email. Alternatively you can create completely new create_user method.
i have same issue and solved problem by adding user argument in create user field ..
None: Argument 'username' is needed for social-auth. It is not actually used.
class UserManager(BaseUserManager):
def create_user(self, email,username=None, full_name=None, password='&btCqv"}#,4TWd6A'):
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.set_password(password) # change user password
user.staff = is_staff
user.admin = is_admin
user.is_active = is_active
user.save(using=self._db)
return user
if still problem persist refer: https://github.com/python-social-auth/social-app-django/issues/15#issuecomment-276118574

Categories