I extended default User model as follow:
class CustomUser(AbstractUser):
email = models.EmailField(_('email address'), unique=True)
first_name = models.CharField(max_length = 100, blank = False)
last_name = models.CharField(max_length = 100, blank = False)
is_teacher models.BooleanField(default = False)
...
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'username','password', 'is_teacher']
Now when creating a new superuser the prompt for password is not hidden
$ python manage.py createsuperuser
Email address: user1#coolapp.com
First name: John
Last name: Smith
Username: cool_username
Is teacher: True
Password: fancy_p4$$w0rd
Superuser created successfully.
Is there any way it can be hidden?
When defining REQUIRED_FIELDS in the CustomUser model, just skip password. The default password prompt will show up after the list is iterated completely:
REQUIRED_FIELDS = ['first_name', 'last_name', 'username', 'is_teacher']
Now when creating a new superuser:
$ python manage.py createsuperuser
Email address: user1#coolapp.com
First name: John
Last name: Smith
Username: cool_username
Is teacher: True
Password:
Password (again):
Superuser created successfully.
Related
So I have created a custom User model and a common model as base for all other models that adds a created_by field.
If I now use the Django admin page to create an object(just for testing) then I get the error that the UID is Null.
class UserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
"""Creates and saves a new User"""
if not email:
raise ValueError("Users must have an email address")
user = self.model(email=self.normalize_email(email), **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password):
"""creates and saves a new superuser"""
user = self.create_user(email, password)
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class CommonModel(models.Model):
"""Common fields that are shared among other models"""
created_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.PROTECT,
editable=False,
related_name="+",
)
class User(AbstractBaseUser, PermissionsMixin):
"""Custom user model that supports using email instead of username"""
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = "email"
I get this error:
IntegrityError at /admin/core/tenant/add/
null value in column "created_by_id" of relation "core_tenant" violates not-null constraint
DETAIL: Failing row contains (3, 2022-05-20 15:11:27.755389+00, 2022-05-20 15:11:27.755413+00, test1234, blablka, null, null, null, null).
Request Method: POST
Request URL: http://127.0.0.1:8900/admin/core/tenant/add/
Django Version: 4.0.4
Exception Type: IntegrityError
Exception Value:
null value in column "created_by_id" of relation "core_tenant" violates not-null constraint
DETAIL: Failing row contains (3, 2022-05-20 15:11:27.755389+00, 2022-05-20 15:11:27.755413+00, test1234, blablka, null, null, null, null).
Exception Location: /py/lib/python3.9/site-packages/django/db/backends/utils.py, line 89, in _execute
Python Executable: /py/bin/python
Python Version: 3.9.9
Python Path:
['/fwmodule',
'/usr/local/lib/python39.zip',
'/usr/local/lib/python3.9',
'/usr/local/lib/python3.9/lib-dynload',
'/py/lib/python3.9/site-packages']
Server time: Fri, 20 May 2022 15:11:27 +0000
So it seems like when using the admin page to create objects the UID cannot be resolved.
Any ideas?
I am using social-auth-app-django for signup-signin of new users using google oauth2 authentication.
after signup a new user is created in my db but the is_active is set as false, I want to set is_active as true only for users created by this social_auth google authentication
(for other users who sign up using email-password I activate them by sending an account activation email)
I have tried setting is_active = True for all users with no password , but I feel this way is insecure and hackish .
How do I modify the social_auth_login flow to activate users as well ?
I am using a custom User model :
class UserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError('The Email must be set')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
if password:
user.set_password(password)
# else:
# user.is_active = True <-------- tried this , worked too
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_active', True)
extra_fields.setdefault('user_type', user_constants.SUPERUSER)
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)
..
class User(AbstractUser):
username = None # remove username field, we will use email as unique identifier
email = models.EmailField(unique=True, null=True, db_index=True)
client_id = models.UUIDField(primary_key = True,
default = uuid.uuid4,
editable = False)
name = models.CharField(max_length=255, default="")
is_active = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
date_joined = models.DateTimeField(default=timezone.now)
user_type = models.PositiveSmallIntegerField(choices=user_constants.USER_TYPE_CHOICES, default=user_constants.CLIENT_ADMIN)
REQUIRED_FIELDS = []
USERNAME_FIELD = 'email'
objects = UserManager()
..
SOCIAL_AUTH_PIPELINE = (
'social_core.pipeline.social_auth.social_details',
'social_core.pipeline.social_auth.social_uid',
'social_core.pipeline.social_auth.auth_allowed',
'social_core.pipeline.social_auth.social_user',
'social_core.pipeline.user.get_username',
'social_core.pipeline.social_auth.associate_by_email',
'social_core.pipeline.user.create_user',
'social_core.pipeline.social_auth.associate_user',
'social_core.pipeline.social_auth.load_extra_data',
'social_core.pipeline.user.user_details',
)
SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL = True
SOCIAL_AUTH_USER_MODEL = 'register.User'
SOCIAL_AUTH_GOOGLE_OAUTH2_USER_FIELDS = ['email']
..
According to Django, the boolean is_active
designates whether this user account should be considered active. We
recommend that you set this flag to False instead of deleting
accounts; that way, if your applications have any foreign keys to
users, the foreign keys won’t break.
In your case, I would put is_active as True by default (if you want to delete an account, you just put it False).
Following your remark
(for other users who sign up using email-password I activate them by
sending an account activation email)
you can add a boolean is_email_verified : if the user is created by social auth, it means the is_email_verified is True; if the user is created following email-password, is_email_verified is False and must be set to True by sending an account activation email.
Thanks to that you can have 4 states with the 2 booleans is_active and is_email_verified : a user who wants to connect must have both of them as True. It seems secure to me.
I am working on a django (1.8.6) site that involved two applications now. One is a custom user model with basic registration / login / logout functionality, the second is a feedback application. I want to have a foreign key relationship from a feedback to the user that submitted it.
When I try to run ./manage.py migrate I get the following error.
django.db.utils.ProgrammingError: relation "customauth_user" does not exist
This is of course since the database table does not YET exist. If I remove the related field, everything works fine. Here is my code.
My user model:
class User(AbstractBaseUser):
username = models.CharField(_('username'), max_length=100, unique=True)
email = models.EmailField(('email address'), max_length=254)
first_name = models.CharField(_('first name'), max_length=50)
last_name = models.CharField(_('lat_name'), max_length=50)
receive_newsletter = models.BooleanField(_('receive_newsletter'), default=False)
referral_id = models.CharField(_('referral id'), max_length=40)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email', 'first_name', 'last_name']
And the model from my feedback form:
class Feedback(models.Model):
timestamp = models.DateTimeField(auto_now_add=True)
submitted_by = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='feedback')
title = models.CharField(max_length=100)
message = models.CharField('Users message', max_length=1024)
reviewed = models.BooleanField('Reviewed by staff', default='NEW', choices=FEEDBACK_STATUS_CHOICES, max_length=10)
jira_ticket_created = models.BooleanField('Created a Jira ticket to track this feedback.',
default=False)
jira_ticket_number = models.CharField(max_length=10, blank=True, null=True)
class Meta:
db_table = 'feedback'
def __str__(self):
return str(self.timestamp) + ' ' + self.title
I have configured my user model in settings, added both applications, and in my installed applications my applcaition with my custom user model is first.
Any thoughts?
Thanks
Craig
You need to add a dependency in your feedback migration to the customauth app. See the migrations docs.
You should use python manage.py makemigrations
and then python manage.py migrate
I have defined a custom user model class as follows
class LabUserManager(BaseUserManager):
"""
A new user manager for both standard and administrative users
"""
def create_user(
self,
email,
first_name,
last_name,
university,
job_title,
bio,
password=None
):
"""
Creates a standard user with no administrative privledges
"""
if not email:
raise ValueError('Users must provide an email')
if not first_name:
raise ValueError('Users must provide a first name')
if not last_name:
raise ValueError('Users must provide a last name')
if not university:
raise ValueError('Users must provide an email address')
# Note: a biography and job_title are not required
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(
self,
email,
first_name,
last_name,
university,
job_title,
bio,
password=None
):
"""
Creates an administrative user
"""
user = self.create_user(
self,
email,
first_name,
last_name,
university,
job_title,
bio,
password=None
)
user.is_admin = True
user.save(using=self._db)
return user
class LabUser(AbstractBaseUser):
"""
Model for every user on the site
The only required fields are:
email,
first_name,
last_name,
university,
although, this will be discussed later
"""
email = models.EmailField(
verbose_name = 'email address',
max_length = 255,
unique = True,
db_index = True,
)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
university = models.CharField(max_length=150)
job_title = models.CharField(max_length = 50)
bio = models.TextField()
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
objects = LabUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = [
'first_name',
'last_name',
'university',
]
#property
def is_staff(self):
return self.is_admin
With the serializer
class NewUserSerializer(serializers.Serializer):
"""
Defines a new user serializer
"""
pk = serializers.Field()
email = serializers.EmailField()
first_name = serializers.CharField(max_length=50)
last_name = serializers.CharField(max_length=50)
university = serializers.CharField(max_length=150)
job_title = serializers.CharField(
max_length=50,
required=False
)
bio = serializers.CharField(
widget=widgets.Textarea,
required=False
)
password = serializers.CharField(
max_length=64,
widget=widgets.PasswordInput
)
def restore_object(self, attrs, instance=None):
if instance: # Update email university bio or job_title
user = instance
user.email = attrs['email']
user.university = attrs['university']
user.bio = attrs['bio']
user.job_title = attrs['job_title']
user.set_password(attrs.get('password'))
else:
user = LabUser(
email=attrs['email'],
first_name=attrs['first_name'],
last_name=attrs['last_name'],
university=attrs['university'],
job_title=attrs['job_title'],
bio=attrs['bio']
# Check custom user model page for other parameters
)
user.set_password(attrs.get('password'))
user.save()
return user
with the View
class NewUser(generics.CreateAPIView):
serializer_class = NewUserSerializer
But when I post a new user with a new email address, I receive the following error
IntegrityError at /users/new/
PRIMARY KEY must be unique
Request Method: POST
Request URL: http://127.0.0.1:8000/users/new/
Django Version: 1.5.1
Exception Type: IntegrityError
Exception Value:
PRIMARY KEY must be unique
At some point, you seem to submit and process a primary key value when creating new objects. It's only a guess, but I think this happens somewhere in your NewUserSerializer because you explicitly added a pk field, that is not read only and does not enforce a positive integer value. I would try using an IntegerField with read_only=True instead and see if that fixes the problem.
But I strongly recommend using ModelSerializer anyway. You could still have your custom widgets for each field, but it would also handle a few things a little more concise than your implementation does. And you'd have to write much less code.
my goal is to create a custom user model in Django 1.5
# myapp.models.py
from django.contrib.auth.models import AbstractBaseUser
class MyUser(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
db_index=True,
)
first_name = models.CharField(max_length=30, blank=True)
last_name = models.CharField(max_length=30, blank=True)
company = models.ForeignKey('Company')
...
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['company']
I can't create a super user because of the company field (models.ForeignKey('Company') (python manage.py createsuperuser).
My question:
How can I create a super user for my application without a company.
I tried to make a custom MyUserManager without any success:
class MyUserManager(BaseUserManager):
...
def create_superuser(self, email, company=None, password):
"""
Creates and saves a superuser with the given email and password.
"""
user = self.create_user(
email,
password=password,
)
user.save(using=self._db)
return user
Or do I have to create a fake company for this user?
Thank you
There are three ways for you in this case
1) Make relation to company Not required company = models.ForeignKey('Company', null=True)
2) Add default company and provide it as default value to foreign key field company = models.ForeignKey('Company', default=1) #where 1 is id of created company
3) Leave model code as is. Add fake company for superuser named for example 'Superusercompany'
set it in create_superuser method.
UPD: according to your comment way #3 would be the best solution not to break your business logic.
Thanks to your feedback here is the solution I made:
A custom MyUserManager where I created a default company
def create_superuser(self, email, password, company=None):
"""
Creates and saves a superuser with the given email and password.
"""
if not company:
company = Company(
name="...",
address="...",
code="...",
city="..."
)
company.save()
user = self.create_user(
email,
password=password,
company=company
)
user.is_admin = True
user.save(using=self._db)
return user