I am have created a custom user model to replace username with email. But when I am trying to add user from Django Admin I get error:
Please correct the errors below.
There is no other information with that error message.
The code for custom user:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(
verbose_name="email_address",
max_length=255,
unique=True,
)
name = models.CharField(max_length=255)
is_staff = models.BooleanField(
default=False,
)
is_active = models.BooleanField(
default=True,
)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
def get_full_name(self):
return self.name
def __str__(self):
return self.email
Custom User Manager Code:
class UserManager(BaseUserManager):
def _create_user(self, email, password, **kwargs):
if not email:
raise ValueError("Email is required")
email = self.normalize_email(email)
user = self.model(email=email, **kwargs)
user.set_password(password)
user.save()
return user
def create_user(self, email, password=None, **extra_fields):
"""Create and save a regular User with the given email and password."""
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, **kwargs):
kwargs.setdefault('is_staff', True)
kwargs.setdefault('is_superuser', True)
kwargs.setdefault('is_active', 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)
and the admin code for same:
class CustomUserAdmin(BaseUserAdmin):
add_form = CustomUserCreationForm
form = CustomUserCreationForm
list_display = ('id', 'email', 'is_superuser')
list_filter = ('is_superuser',)
fieldsets = (
(None, {'fields': ('name', 'email', 'password')}),
('Permissions', {'fields': ('is_superuser', 'is_staff')}),
)
add_fieldsets = fieldsets
search_fields = ('name', 'email')
ordering = ('name', 'email')
filter_horizontal = ()
Custom User Form:
# users/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import User
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = User
fields = ('name', 'email')
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = User
fields = ('name', 'email')
I have tried many changes but couldn't figure out the issue. I would appreciate any help on this.
Change:
class Meta:
model = User
fields = ('name', 'email')
To:
class Meta(UserCreationForm.Meta):
model = User
fields = UserCreationForm.Meta.fields + ('name', 'email')
Related
I'm trying to Override the user model to make usernames case insensitive and allow semicolons. I haven't added the code for semicolons yet. I am getting a matching query error while trying to create a superuser.
When I run python manage.py createsuperuser I get a matching query error
Here is my code
models.py
from django.db import models
from django.contrib.auth.models import (
AbstractBaseUser, BaseUserManager
)
class UserManager(BaseUserManager):
def get_by_natural_key(self, username):
return self.get(**{self.model.USERNAME_FIELD + '__iexact': username})
def create_user(self, username, password=None, is_active=True, is_staff=False, is_admin=False):
if not username:
raise ValueError("Users must have an username address")
if not password:
raise ValueError("Users must have a password")
user_obj = self.model(
username = self.get_by_natural_key(username)
)
user_obj.set_password(password) # change user password
user_obj.staff = is_staff
user_obj.admin = is_admin
user_obj.active = is_active
user_obj.save(using=self._db)
return user_obj
def create_staffuser(self, username, password=None):
user = self.create_user(
username,
password=password,
is_staff=True
)
return user
def create_superuser(self, username, password=None):
user = self.create_user(
username,
password=password,
is_staff=True,
is_admin=True
)
return user
class User(AbstractBaseUser):
username = models.CharField(max_length=255, unique=True)
#full_name = models.CharField(max_length=255, blank=True, null=True)
active = models.BooleanField(default=True) # can login
staff = models.BooleanField(default=False) # staff user non superuser
admin = models.BooleanField(default=False) # superuser
timestamp = models.DateTimeField(auto_now_add=True)
# confirm = models.BooleanField(default=False)
# confirmed_date = models.DateTimeField(default=False)
USERNAME_FIELD = 'username' #username
# USERNAME_FIELD and password are required by default
REQUIRED_FIELDS = [] #['full_name'] #python manage.py createsuperuser
objects = UserManager()
def __str__(self):
return self.username
def get_full_name(self):
return self.username
def get_short_name(self):
return self.username
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
def is_staff(self):
return self.staff
def is_admin(self):
return self.admin
def is_active(self):
return self.active
admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
User = get_user_model()
class UserAdmin(BaseUserAdmin):
list_display = ('username', 'admin')
list_filter = ('admin', 'staff', 'active')
fieldsets = (
(None, {'fields': ('username', 'password')}),
('Personal info', {'fields': ()}),
('Permissions', {'fields': ('admin', 'staff', 'active',)}),
)
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'password1', 'password2')}
),
)
search_fields = ('username',)
ordering = ('username',)
filter_horizontal = ()
admin.site.register(User, UserAdmin)
Here is the error that I'm getting
account.models.DoesNotExist: User matching query does not exist.
I am creating a custom user class for my data base but I can't get my custom fields to show in the admin portal when adding a new user or changing an existing user. I have registered the app in my settings, migrated the data base, and set the AUTH_USER_MODEL in my settings.py. Thank you!
My admin portal looks like this:
And my files look like this:
models.py
from django.db import models
from django.core.mail import send_mail
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUser
from django.utils.translation import ugettext_lazy as _
import secrets
from api_keys.managers import *
class User(AbstractBaseUser, PermissionsMixin):
FULL = 4
MAJOR = 3
MINOR = 2
CONTROLLED = 1
access_groups = [(FULL, 4), (MAJOR, 3), (MINOR, 2), (CONTROLLED, 1)]
username = models.CharField(_('user name'), max_length=50, unique=True)
email = models.EmailField(_('email address'), unique=True)
first_name = models.CharField(_('first name'), max_length=50, blank=True)
last_name = models.CharField(_('last name'), max_length=50, blank=True)
account_name = models.TextField(_('account'), max_length=500, blank=True)
purpose = models.TextField(_('purpose'), max_length=5000, blank=True)
date_joined = models.DateTimeField(_('date joined'), auto_now_add=True)
is_active = models.BooleanField(_('active'), default=True)
is_staff = models.BooleanField(_('staff'), default=False)
access_group = models.IntegerField(_('permission group'), choices=access_groups, default=CONTROLLED)
api_key = models.CharField(_('api key'), max_length=100)
delete_on = models.DateField(_('deletion date'), blank=True, null=True)
objects = UserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email', 'access_group']
def save(self, *args, **kwargs):
if not self.api_key:
self.api_key = secrets.token_urlsafe(16)
super(User, self).save(*args, **kwargs)
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def has_access(self, level):
return self.access_group >= level
def email_user(self, subject, message, from_email=None, **kwargs):
send_mail(subject, message, from_email, [self.email], **kwargs)
managers.py
from django.contrib.auth.base_user import BaseUserManager
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, username, email, password, **extra_fields):
if not username:
raise ValueError('The given user name must be set')
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
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, email, password=None, **extra_fields):
extra_fields.setdefault('is_superuser', False)
extra_fields.setdefault('is_staff', False)
return self._create_user(username, email, password, **extra_fields)
def create_superuser(self, username, email, password=None, **extra_fields):
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_staff', True)
if not extra_fields.get('is_superuser'):
raise ValueError('Superuser must have is_superuser = True')
return self._create_user(username, email, password, **extra_fields)
admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from api_keys.forms import UserChangeForm, UserCreationForm
from api_keys.models import User
# Register your models here.
class NewUserAdmin(UserAdmin):
form = UserChangeForm
add_form = UserCreationForm
model = User
list_display = ('username', 'email', 'access_group', 'delete_on', 'api_key')
list_filter = ('username', 'email', 'access_group', 'is_superuser', 'delete_on')
readonly_fields = ['date_joined', 'api_key', 'last_login']
field_sets = (
('User', {'fields': ('username', 'email', 'password', 'access_group')}),
('Permissions', {'fields': (('is_staff', 'is_active'), 'access_group', 'delete_on')}),
)
add_field_sets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'email', ('password1', 'password2'))
}),
('Permissions', {'fields': (('is_staff', 'is_active'), 'access_group', 'delete_on')})
)
search_fields = ('username', 'email', 'first_name', 'last_name', 'account_name', 'access_group', 'delete_on')
ordering = ('username', 'email', 'first_name', 'last_name', 'access_group', 'account_name', 'delete_on')
admin.site.register(User, NewUserAdmin)
forms.py
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from api_keys.models import User
class UserCreationForm(UserCreationForm):
class Meta(UserCreationForm):
model = User
fields = '__all__'
class UserChangeForm(UserChangeForm):
class Meta(UserChangeForm):
model = User
fields = '__all__'
The layout is controlled by ModelAdmin.fieldsets, not field_sets
class NewUserAdmin(UserAdmin):
...
fieldsets = (
('User', {'fields': ('username', 'email', 'password', 'access_group')}),
('Permissions', {'fields': (('is_staff', 'is_active'), 'access_group', 'delete_on')}),
)
My model is relatively simple, but I want users to be member of a club. Superusers are not members of a club.
I decided to use a Custom User Model Extending AbstractBaseUser and created the models, managers and everything works fine. Now I want to extend the model by a property.
models.py:
from .managers import MyUserManager
class K2User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
date_joined = models.DateTimeField(_('date joined'), auto_now_add=True)
is_active = models.BooleanField(_('active'), default=True)
is_staff = models.BooleanField(_('active'), default=True)
# club_name = models.ForeignKey(Clubs, null=True,
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
def get_club_name(self):
return self.club_name
def __str__(self):
return self.email
class Clubs(models.Model):
club_name = models.CharField(max_length=32, unique=True)
club_create_date = models.DateTimeField('date created')
club_address = models.CharField(max_length=200)
email = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, verbose_name=_('user'), on_delete=models.CASCADE)
managers.py
from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import ugettext_lazy as _
class MyUserManager(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)
# club_name = club_name
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_superuser', False)
extra_fields.setdefault('is_staff', False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_staff', True)
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
return self._create_user(email, password, **extra_fields)
how can I add the club name to a normal user, so that he has to be member of a club, but the superuser does not have this property (or just set it null)?
** Edit **
in my admin view I still only see one member for each club - I guess I have to tinker with the admin.py for that?
admin.py:
class K2UserAdmin(UserAdmin):
add_form = K2UserCreationForm
form = K2UserChangeForm
model = K2User
list_display = ('email', 'date_joined', 'is_active',)# 'merchant',)
list_filter = ('email', 'date_joined', 'is_active',)# 'merchant',)
fieldsets = ( (None, { 'fields': ('email', 'password') } ),
('Permissions', { 'fields': ('date_joined', 'is_active') } ), )
add_fieldsets = ( (None, {'classes': ('wide',),
'fields': ('email', 'password1', 'password2', 'date_joined', 'is_active') } ), )
readonly_fields = ('date_joined',)
admin.site.register(K2User, K2UserAdmin)
admin.site.register(Clubs)
The best way to implement this is as follows:
First of all, you need to create one model between Club and User
(rather than create M2M field). I named it Enrollment.
Put Club and User foreign key this model.
So:
class Enrollment(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name=_('enrollment_users'), on_delete=models.CASCADE)
club = models.ForeignKey(Club, related_name=_('enrollment_clubs'), on_delete=models.CASCADE)
If you follow this way, you can do anything you want in this relation in the future.
Hope it help.
I have the following custom user model implementation in my Django application :
users/models.py
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email: str,
password: str, is_staff: bool,
is_superuser: bool, **extra_fields):
"""Creates and saves a User with the given email and password.
"""
email = self.normalize_email(email)
user = self.model(email=email, is_staff=is_staff, is_active=True,
is_superuser=is_superuser, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email: str, password=None, **extra_fields):
return self._create_user(email, password, False, False, **extra_fields)
def create_superuser(self, email: str, password: str, **extra_fields):
return self._create_user(email, password, True, True, **extra_fields)
class User(AbstractUser, UUIDModel):
first_name = models.CharField(max_length=30, blank=True)
last_name = models.CharField(max_length=30, blank=True)
email = models.EmailField(unique=True, db_index=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
date_joined = models.DateTimeField(default=timezone.now)
USERNAME_FIELD = 'email'
objects = UserManager()
class Meta:
verbose_name = 'user'
verbose_name_plural = 'users'
ordering = ('-date_joined', )
def get_full_name(self):
return "{} {}".format(self.first_name, self.last_name)
def get_short_name(self):
return self.first_name
def get_email(self):
return self.email
def __str__(self):
return "{}".format(self.email)
And my change form in admin.py looks like this :
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as AuthUserAdmin
from django.contrib.auth.forms import UserChangeForm as DjangoUserChangeForm
from django.contrib.auth.forms import UserCreationForm as DjangoUserCreationForm
from .models import User
# Forms
# ----------------------------------------------------------------------------
class MyUserCreationForm(DjangoUserCreationForm):
class Meta:
model = User
fields = ("email",)
class MyUserChangeForm(DjangoUserChangeForm):
class Meta:
model = User
fields = '__all__'
# ModelAdmins
# ----------------------------------------------------------------------------
#admin.register(User)
class UserAdmin(AuthUserAdmin):
add_form_template = 'admin/auth/user/add_form.html'
model = User
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ('first_name', 'last_name',)}),
('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser',
'groups', 'user_permissions')}),
('Important dates', {'fields': ('last_login', 'date_joined')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2'),
}),
)
readonly_fields = ('date_joined', 'last_login')
form = MyUserChangeForm
add_form = MyUserCreationForm
list_display = ('email', 'first_name', 'last_name', 'is_active')
list_filter = ('is_superuser', 'is_active')
search_fields = ('first_name', 'last_name', 'email')
ordering = ('email',)
I have added these two lines in my settings.py files.
AUTH_USER_MODEL = 'users.User'
AUTHENTICATION_BACKENDS = (
"django.contrib.auth.backends.ModelBackend",)
I have extended this model to a custom profile model. But when I try to create another user I get the following error django.db.utils.IntegrityError: (1062, "Duplicate entry '' for key 'username'") . Can anybody help me with this?
I am using Django : Django==2.2 with MySql.
Set
USERNAME_FIELD = 'username'
and test your code.
If everything works then change it.
Add username field in your custom user modal
Because error clearly says duplicate entry for key username which means, you have overrides the default user authentication by email id, so every time you create a user blank username tries to be created. Still, Django won't allow it's default implementation to be unique=True, so you have to override the username attribute also.
class User(AbstractUser):
email = models.EmailField(max_length=100, unique=True)
# add the below one line code
username = models.CharField(max_length=100, unique=False, null=True, default=None)
is_deleted = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
I am using Django user model and also extended with my own profile model for some other data.When i want to update user data which is in Profile Model It doesn't get updated because all the user id,username,email,password reside in user model while the fields which are needed to get updated are in profile model.I have used this approach, all it does is takes inputs and displays the response but does not show any change in User Data when viewing it as a whole.
models.py
class Profile(models.Model):
user = models.OneToOneField(User,related_name='profile',on_delete=models.CASCADE)
location = models.CharField(max_length=30,blank=True)
friends_count = models.PositiveIntegerField(default=0)
profile_pic = models.FileField(upload_to='profile_pics/',blank=True,null=True)
def natural_key(self):
return (self.user.username,)
views.py
class UserCreateAPIViewSet(viewsets.ModelViewSet,mixins.UpdateModelMixin):
""""A View which handles Creating and Updating User Profile"""
serializer_class = UserProfileCreateSerializer
queryset = User.objects.all()
authentication_classes = (TokenAuthentication,)
permission_classes = (permissions.UpdateOwnProfile,)
filter_backends = (filters.SearchFilter,)
search_fields = ('username','email',)
class UserUpdateAPI(generics.GenericAPIView,mixins.UpdateModelMixin):
"""Update User Profile Data"""
permission_classes = (permissions.UpdateOwnProfile,)
authentication_classes = (TokenAuthentication,)
queryset = Profile.objects.all()
serializer_class = ProfileUpdateSerializer
def put(self,request,*args,**kwargs):
return self.partial_update(request,*args,**kwargs)
urls.py
url(r'^user-update/(?P<pk>\d+)/$',views.UserUpdateAPI.as_view(),name="user-update"),
router = DefaultRouter()
router.register(r'profile',views.UserCreateAPIViewSet)
serializers.py
class UserProfileCreateSerializer(serializers.ModelSerializer):
""""A serializer for user data request"""
location = serializers.CharField(source='profile.location')
friends_count = serializers.IntegerField(source='profile.friends_count',read_only=True)
profile_pic = serializers.FileField(source='profile.profile_pic',allow_empty_file=True,allow_null=True)
class Meta:
model = User
fields = (
'pk',
'username',
'email',
'password',
'location',
'friends_count',
'profile_pic',
)
extra_kwargs = {
'password':{'write_only':True},
'friends_count':{'read_only':True},
}
def create(self, validated_data):
""""Create and return a new User"""
user = User(
email = validated_data['email'],
username = validated_data['username']
)
user.set_password(validated_data['password'])
user.save()
return user
class ProfileUpdateSerializer(serializers.ModelSerializer):
"""A serializer for updating user data"""
class Meta:
model = Profile
fields = ('location','profile_pic')
Looks like you want to extend from the AbstractBaseUser (see code below), using this as your UserProfileCreateSerializer:
class UserProfileCreateSerializer(serializers.ModelSerializer):
""""A serializer for user data request"""
location = serializers.CharField(source='profile.location')
friends_count = serializers.IntegerField(source='profile.friends_count',read_only=True)
profile_pic = serializers.FileField(source='profile.profile_pic',allow_empty_file=True,allow_null=True)
class Meta:
model = Profile
fields = (
'pk',
'username',
'email',
'password',
'location',
'friends_count',
'profile_pic',
)
extra_kwargs = {
'password':{'write_only':True},
'friends_count':{'read_only':True},
}
def create(self, validated_data):
""""Create and return a new User"""
user = Profile(
email = validated_data['email'],
username = validated_data['username']
)
user.set_password(validated_data['password'])
user.save()
return user
class ProfileUpdateSerializer(serializers.ModelSerializer):
"""A serializer for updating user data"""
class Meta:
model = Profile
fields = ('location','profile_pic')
Then extend from the AbstractBaseUser in models.py:
from __future__ import unicode_literals
from django.db import models
from django.core.mail import send_mail
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUser
from django.utils.translation import ugettext_lazy as _
from .managers import ProfileManager
class Profile(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
username = models.CharField(_('first name'), max_length=30, blank=True)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
date_joined = models.DateTimeField(_('date joined'), auto_now_add=True)
is_active = models.BooleanField(_('active'), default=True)
location = models.CharField(max_length=30,blank=True)
friends_count = models.PositiveIntegerField(default=0)
profile_pic = models.FileField(upload_to='profile_pics/',blank=True,null=True)
objects = UserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = []
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def get_full_name(self):
'''
Returns 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):
'''
Returns the short name for the user.
'''
return self.first_name
def natural_key(self):
return (self.username,)
def email_user(self, subject, message, from_email=None, **kwargs):
'''
Sends an email to this User.
'''
send_mail(subject, message, from_email, [self.email], **kwargs)
And then create a file called managers.py in the same directory as models.py:
from django.contrib.auth.base_user import BaseUserManager
class ProfileManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
"""
Creates and saves a User with the given email and password.
"""
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_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)
To wrap all this up you need to add this to your settings.py file:
AUTH_USER_MODEL = 'app.Profile'
And also don't forget to re-run all database migrations before using $ python manage.py runserver.