django admin not working with custom user - django

I feel like I'm missing somehting obvious on this one.
I've created a custom user and user manger
class UserManager(BaseUserManager):
# create a normal user
# an email and password must be provided
def create_user(self, email, password, first_name, last_name,
location, date_of_birth):
if not email:
raise ValueError("User must have an email")
if not password:
raise ValueError("User must have a password")
email = email.lower()
user = self.model(
email=email,
first_name=first_name,
last_name=last_name,
location=location,
date_of_birth=date_of_birth
)
user.set_password(password)
user.save(using=self._db)
return user
# Make an administrator
def create_superuser(self, email, password, first_name, last_name,
location, date_of_birth):
user = self.create_user(
email=email,
password=password,
first_name=first_name,
last_name=last_name,
location=location,
date_of_birth=date_of_birth
)
user.is_admin = True
user.is_moderator = True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True
)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
location = models.ForeignKey(Location)
date_of_birth = models.DateField()
date_joined = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_moderator = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'location', 'date_of_birth']
def __unicode__(self):
return self.email
def get_full_name(self):
return self.first_name + ' ' + self.last_name
def get_age(self):
age = date.today() - self.date_of_birth
return age.days / 365
def is_staff(self):
return self.is_admin
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
However if I visit the admin site, It will happily authorize a user who is not an admin is_admin=False
Has anyone run into this problem, Is there something I need to change when using django admin with a custom user?
EDIT
setting.py
AUTH_USER_MODEL = 'userAccount.User'
AUTHENTICATION_BACKEND = (
'django.contrib.auth.backends.ModelBackend',
)

is_admin is not something that django's authentication system knows about. In the authentication form that is used, it is only checking if the user is active or is staff:
class AdminAuthenticationForm(AuthenticationForm):
"""
A custom authentication form used in the admin app.
"""
error_messages = {
'invalid_login': _("Please enter the correct %(username)s and password "
"for a staff account. Note that both fields may be "
"case-sensitive."),
}
required_css_class = 'required'
def confirm_login_allowed(self, user):
if not user.is_active or not user.is_staff:
raise forms.ValidationError(
self.error_messages['invalid_login'],
code='invalid_login',
params={'username': self.username_field.verbose_name}
)
In the original user model, is_staff is a model field. You do not have such a field, but rather a method. This could be a why its not working.
You can solve this problem two ways:
Create your own AdminAuthenticationForm and adjust the confirm_login_allowed method to check for is_admin rather than is_staff.
Create a is_staff property in your custom user model:
#property
def is_staff(self):
return self._is_admin

Related

How can i make a custom user model in django without using username field?

I am working on building a project and for this, i need to create a custom user model, since the one that Django comes with isn't suitable for my situation, so whenever i use the AbstractBaseUser, I am forced to use the username field, which i really don't need in my case. how can I create a custom user model without using the username field and thank you
After many attempts, i finally could fix it by overiding it in the accountmanager
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
import uuid
class MyAccountManager(BaseUserManager):
def _create_user(self, email, first_name, last_name, password=None):
if not email:
raise ValueError("Users must have an email address")
if not first_name:
raise ValueError("Users must have an userusername")
if not last_name:
raise ValueError("Users must have an userusername")
user = self.model(
email=self.normalize_email(email),
first_name=first_name,
last_name=last_name,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email,first_name, last_name, password):
user = self._create_user(
email=self.normalize_email(email),
password=password,
first_name= first_name,
last_name=last_name,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.is_active = True
user.save(using=self._db)
return user
def verifyAccount(self, user, user_input, code):
if user_input == code:
user.is_active = True
user.save(using=self._db)
return user
class Account(AbstractBaseUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.EmailField(verbose_name="email", max_length=60, unique=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name']
objects = MyAccountManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True

How to use post_save signal with custom user model extended with AbstractBaseUser

There are two apps in my ecommerce website and i have been following a particular tutorial on youtube. In the course, the guy used django-allauth package for login purposes. I followed the course along but I created custom user model exending AbstracBaseUser class in account app.
I created another app called product where I handled all the ecommerce logics.
Here's the code:
models.py (account)
class MyAccountManager(BaseUserManager):
def create_user(self, email, username, first_name, last_name, gstin_no, phone_no, password=None):
if not email:
raise ValueError("Users must have an email address")
if not username:
raise ValueError("Users must have a username")
if not first_name:
raise ValueError("Users must have First Name")
if not last_name:
raise ValueError("Users must have Last Name")
if not gstin_no:
raise ValueError("Users must have a valid GSTIN Number")
if not phone_no:
raise ValueError("Users must have a valid Phone Number")
user = self.model(
email=self.normalize_email(email),
username=username,
first_name=first_name,
last_name=last_name,
gstin_no=gstin_no,
phone_no=phone_no,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, first_name, last_name, gstin_no, phone_no, password):
user = self.create_user(
email=self.normalize_email(email),
password=password,
username=username,
first_name=first_name,
last_name=last_name,
gstin_no=gstin_no,
phone_no=phone_no,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name="email", max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
first_name = models.CharField(verbose_name="first name", max_length=20)
last_name = models.CharField(verbose_name="last name", max_length=20)
gstin_no = models.CharField(verbose_name='gstin no', max_length=15, unique=True)
phone_no = models.BigIntegerField(unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', 'first_name', 'last_name', 'gstin_no', 'phone_no', ]
objects = MyAccountManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
models.py (product)
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
stripe_customer_id = models.CharField(max_length=50, blank=True, null=True)
one_click_purchasing = models.BooleanField()
def __str__(self):
return self.user.username
def userprofile_receiver(sender, instance, created, *args, **kwargs):
if created:
userprofile = UserProfile.objects.create(user=instance)
post_save.connect(userprofile_receiver, sender=settings.AUTH_USER_MODEL)
views.py (product)
class PaymentView(LoginRequiredMixin, View):
def get(self, *args, **kwargs):
order = Order.objects.get(user=self.request.user, ordered=False)
if order.billing_address:
context = {
'order': order,
'DISPLAY_COUPON_FORM': False
}
userprofile = self.request.user.userprofile
if userprofile.one_click_purchasing:
#fetch the user's card list
cards = stripe.Customer.list_sources(
userprofile.stripe_customer_id,
limit = 3,
object = 'card'
)
card_list = cards['data']
if len(card_list) > 0:
# update the card with the default card
context.update({
'card': card_list[0]
})
return render(self.request, 'product/payment.html', context)
else:
messages.warning(self.request, "You have not added a billing address.")
return redirect("checkout")
The error I am getting is:
RelatedObjectDoesNotExist at /payment/stripe/
Account has no userprofile.
How can I get this working. I am not able to get the concept here about what's wrong.
Go to django admin and check is that userprofile created for that user.If not, Then it is possible you have added user before adding this signal functionality. create new user and check userprofile. If still not created. There is something wrong with your signal.

parse_datetime match = datetime_re.match(value) TypeError: expected string or bytes-like object

I have the error with this models.py ?
This replace built-in User model.
Errors are detected in line user_obj.save(using=self._db) in def UserManager
and in line def create_superuser user = self.create_user(
email,
last_name=last_name,
first_name=first_name,
password=password,
)
It seems like it does not like my timestamp attribute with date value ?
thanks
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser
)
class UserManager(BaseUserManager):
def create_user(self, email, last_name, first_name, password=None, is_active=True, is_staff=False, is_admin=False):
"""
Creates and saves a User with the given email and password.
"""
if not email:
raise ValueError('Users must have an email address')
if not password:
raise ValueError('Users must have a password')
user_obj = self.model(
email=self.normalize_email(email),
)
user_obj.set_password(password) # change user password
user_obj.first_name = first_name
user_obj.last_name = last_name
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, email, password):
"""
Creates and saves a staff user with the given email and password.
"""
user = self.create_user(
email,
password=password,
)
user.staff = True
user.save(using=self._db)
return user
def create_superuser(self, email,last_name, first_name, password):
"""
Creates and saves a superuser with the given email and password.
"""
user = self.create_user(
email,
last_name=last_name,
first_name=first_name,
password=password,
)
user.staff = True
user.admin = True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
first_name = models.CharField(max_length=255, blank=False, null=False)
last_name = models.CharField(max_length=255, blank=False, null=False)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False) # a admin user; non super-user
admin = models.BooleanField(default=False) # a superuser
timestamp = models.DateTimeField(default=timezone.now)
confirmedEmail = models.BooleanField(default=False) # Check if user is valid
confirmedDate = models.DateTimeField(default=False) # Check if user is valid
# notice the absence of a "Password field", that's built in.
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name'] # Email & Password are required by default.
def get_full_name(self):
# The user is identified by their email address
return "%s %s" % (self.first_name, self.last_name)
def get_short_name(self):
# The user is identified by their email address
return self.email
def __str__(self): # __unicode__ on Python 2
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?"
return self.staff
#property
def is_admin(self):
"Is the user a admin member?"
return self.admin
#property
def is_active(self):
"Is the user active?"
return self.active
objects = UserManager()
I find the issue.
confirmedDate = models.DateTimeField(default=False)
It cannot be default= false as it is a datefield. Good answer is:
confirmedDate = models.DateTimeField(null=True, blank=True)

django AttributeError: dict object has no attribute 'pk'

I'm making a simple django rest framework project.
This is just creating a new user, and logging in.
When I used django basic auth user model, everything worked well.
But after changing basic user model to custom user, this error comes out when creating a new user:
dict object has no attribute 'pk'
Custom user model is made referred to django docs.
Error says that:
File "/home/seokchan/server/mdocker/lib/python3.5/site-packages/django/contrib/auth/__init__.py",
line 100, in login
if _get_user_session_key(request) != user.pk or ( AttributeError: 'dict' object has no attribute 'pk'
This seems to say that user model has no pk, but I don't get it.
models.py
class MyUserManager(BaseUserManager):
def create_user(self, username, email, password=None):
if not email:
raise ValueError('Users must have an email address')
if not username:
raise ValueError('Users must have an user name')
user = self.model(
email=self.normalize_email(email),
username = username
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, username, email, password):
user = self.create_user(
username,
password=password,
email = email,
)
user.is_admin = True
user.save(using=self._db)
return user
class MyUser(AbstractBaseUser):
id = models.AutoField(primary_key=True)
username = models.CharField(
verbose_name='user name',
max_length=30,
unique=True,
)
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
sth_test = models.TextField(blank = True)
objects = MyUserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
def __str__(self):
return self.username
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
serializers.py
class CreateUserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model
fields = ('id', 'username', 'email', 'password', 'is_active')
email = serializers.EmailField(
required=True,
validators=[UniqueValidator(queryset=User.objects.all())]
)
username = serializers.CharField(
max_length=32,
validators=[UniqueValidator(queryset=User.objects.all())]
)
password = serializers.CharField(min_length=8, write_only=True)
def validate_email(self,value):
if User.objects.filter(email=value).exists():
raise serializers.ValidationError("err.")
return value
def create(self, validated_data):
user = User.objects.create_user(
validated_data['username'],
validated_data['email'],
validated_data['password'],
)
user.is_active = False
user.save()
message=render_to_string('accounts/account_activate_email.html',{
'user':user,
'domain':'localhost:8000/api/accounts/activate',
'uid':urlsafe_base64_encode(force_bytes(user.pk)).decode('utf-8'),
'token':account_activation_token.make_token(user)
})
mail_subject = 'Bplus'
to_email = user.email
AuthEmail = EmailMessage(mail_subject, message, to=[to_email])
AuthEmail.send()
return validated_data
views.py
class UserCreateAPI(generics.GenericAPIView):
serializer_class = CreateUserSerializer
def post(self, request, *args, **kwargs):
if len(request.data["username"]) < 4 or len(request.data["password"]) < 8:
body = {"message":"short field"}
return Response(body, status = 400)
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
user_for_auth = User.objects.get(username=user['username'])
login(request, user)
return Response(
{
"user":UserSerializer(
user, context=self.get_serializer_context()
).data,
"token":AuthToken.objects.create(user_for_auth),
}
)
How can I fix this error?
Your serializer create method returns the validated data instead of the created object. Since that is a dict, that is what you end up passing to the login function.
You should have return user instead of return validated_data.

Django custom user model: How to manage staff permissions?

I'm trying to benefit from Django 1.5 and created custom user model. In order to use builtin permissions, which I would like to limit access with in the admin interface. I inherited my user class also from PermissionMixin. But when I create new user and check Staff box, the new user gets all the access that superuser has.
What am I doing wrong?
models.py
class MyUserManager(BaseUserManager):
def create_user(self, email, password=None):
if not email:
raise ValueError(_('Users must have an email address'))
user = self.model(email=MyUserManager.normalize_email(email),)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password):
user = self.create_user(email, password=password,)
user.is_superuser = True
user.is_staff = True
user.save(using=self._db)
return user
class MyUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, db_index=True,)
is_active = models.BooleanField(_('active'), default=True,
help_text=_('Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.'))
is_staff = models.BooleanField(_('staff status'), default=False,
help_text=_('Designates whether the user can log into this admin site.'))
objects = MyUserManager()
USERNAME_FIELD = 'email'
I had the same problem , in my case I had this:
class Estudiante(AbstractBaseUser,PermissionsMixin):
name = models.CharField(max_length=250,null=False,blank=False)
email = models.EmailField(
verbose_name='Direccion de correo Electronico',
max_length=255,
unique=True,
db_index=True,
)
is_staff = models.BooleanField(u'staff status', default=False,
help_text=u'Designates whether the user can log into this admin '
'site.')
is_active = models.BooleanField(u'active', default=True,
help_text=u'Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.')
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
def get_full_name(self):
# The user is identified by their email address
return self.name
def get_short_name(self):
# The user is identified by their email address
return self.email
def __unicode__(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
and MyUserManager:
class MyUserManager(BaseUserManager):
def create_user(self, name,email, password=None):
....
return user
def create_superuser(self, name,email, password):
"""
Creates and saves a superuser with the given email, date of
birth and password.
"""
user = self.model(
email=MyUserManager.normalize_email(email),
name=name,
)
user.is_staff = True
user.is_active = True
user.is_superuser = True
user.set_password(password)
user.save(using=self._db)
return user
I fixed the problem commented or eliminate the methods "has_perm" and has_module_perms
class Estudiante(AbstractBaseUser,PermissionsMixin):
name = models.CharField(max_length=250,null=False,blank=False)
email = models.EmailField(
verbose_name='Direccion de correo Electronico',
max_length=255,
unique=True,
db_index=True,
)
is_staff = models.BooleanField(u'staff status', default=False,
help_text=u'Designates whether the user can log into this admin '
'site.')
is_active = models.BooleanField(u'active', default=True,
help_text=u'Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.')
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
def get_full_name(self):
# The user is identified by their email address
return self.name
def get_short_name(self):
# The user is identified by their email address
return self.email
def __unicode__(self):
return self.email
I've rewritten custom user model. The main difference from the django user model now is that mine does not have username field. Here is the code:
import warnings
from django.core.exceptions import ImproperlyConfigured
from django.core.mail import send_mail
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin,\
SiteProfileNotAvailable, BaseUserManager
from django.utils import timezone
from django.utils.http import urlquote
from django.utils.translation import ugettext_lazy as _
class CustomUserManager(BaseUserManager):
def create_user(self, email=None, password=None, **extra_fields):
"""
Creates and saves a User with the given email and password.
"""
now = timezone.now()
if not email:
raise ValueError('The given email must be set')
email = CustomUserManager.normalize_email(email)
user = self.model(email=email,
is_staff=False, is_active=True, is_superuser=False,
last_login=now, date_joined=now, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password, **extra_fields):
u = self.create_user(email, password, **extra_fields)
u.is_staff = True
u.is_active = True
u.is_superuser = True
u.save(using=self._db)
return u
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
middle_name = models.CharField(_('middle name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
is_staff = models.BooleanField(_('staff status'), default=False,
help_text=_('Designates whether the user can log into this admin '
'site.'))
is_active = models.BooleanField(_('active'), default=True,
help_text=_('Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.'))
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
objects = CustomUserManager()
USERNAME_FIELD = 'email'
def get_absolute_url(self):
return "/users/%s/" % urlquote(self.username)
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 email_user(self, subject, message, from_email=None):
"""
Sends an email to this User.
"""
send_mail(subject, message, from_email, [self.email])
def get_profile(self):
"""
Returns site-specific profile for this user. Raises
SiteProfileNotAvailable if this site does not allow profiles.
"""
warnings.warn("The use of AUTH_PROFILE_MODULE to define user profiles"
" has been deprecated.",
PendingDeprecationWarning)
if not hasattr(self, '_profile_cache'):
from django.conf import settings
if not getattr(settings, 'AUTH_PROFILE_MODULE', False):
raise SiteProfileNotAvailable(
'You need to set AUTH_PROFILE_MODULE in your project '
'settings')
try:
app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.')
except ValueError:
raise SiteProfileNotAvailable(
'app_label and model_name should be separated by a dot in '
'the AUTH_PROFILE_MODULE setting')
try:
model = models.get_model(app_label, model_name)
if model is None:
raise SiteProfileNotAvailable(
'Unable to load the profile model, check '
'AUTH_PROFILE_MODULE in your project settings')
self._profile_cache = model._default_manager.using(
self._state.db).get(user__id__exact=self.id)
self._profile_cache.user = self
except (ImportError, ImproperlyConfigured):
raise SiteProfileNotAvailable
return self._profile_cache
Now it works and keeps all default permissions. Also note, that for the admin you must rewrite user ModelAdmin and UserCreationForm along with UserChangeForm classes.
Still relevant |
I had the same problem, only superuser had all permissions.Even if I create staff and assign them permissions, I could log-in using that account but it showed "you dont have permissions to edit or view anything".
But removing "has_perm" and "has_module_perms" from custom user class fixed it.
Thank you