I tried to customize Django User,which worked fine but I lost things like user_permissions.
I don't have user permissions window from which I can give permissions like "can add Product,Can delete cart" etc.
I tried this:
from django.contrib.auth.admin import UserAdmin
fieldsets = UserAdmin.fieldsets + ('Custom fields set', {'fields': ('email', 'staff')}),
and
UserAdmin.fieldsets += ('Custom fields set', {'fields': ('email', 'staff')}),
but these didn't worked for me.
If I try to add 'user_permissions' to fieldsets I get error
" Unknown field 'user_permissions' specified'".
Do I need to define user_permissions fields?
class UserManager(BaseUserManager):
def create_user(self,email,password=None,is_active=True,is_staff=False,is_admin=False):
if not email:
raise ValueError("Users must have email")
if not password:
raise ValueError("Users must have password")
user_obj = self.model(
email = self.normalize_email(email)
)
user_obj.staff = is_staff
user_obj.admin = is_admin
user_obj.active = is_active
user_obj.set_password(password) #inbuild hashing
user_obj.save(using = self._db)
return user_obj
def create_staffuser(self,email,password=None):
user = self.create_user(email,password=password,is_staff=True)
return user
def create_superuser(self,email,password=None):
user = self.create_user(email,password=password,is_staff=True,is_admin=True)
return user
class User(AbstractBaseUser):
email = models.EmailField(unique=True,max_length=255)
# full_name= models.CharField(max_length=100)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False)
admin = models.BooleanField(default=False)
timestamp= models.DateTimeField(auto_now_add=True)
# confirmed= models.BooleanField(default=False) #confirmed email?
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
def __str__(self):
return self.email
def get_full_name(self):
return self.email
def has_perm(self,perm,obj=None):
return True
def has_module_perms(self,app_label):
return True
This is how my admin looks currently.
You have to use PermissionsMixin class while creating the custom user model
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
class User(AbstractBaseUser, PermissionsMixin):
# your fields
Related
I am trying creating a custom user model in django - which I am using as a backend. On django admin I can create users without issue. My problem arises when I try to register a new account via postman.
In postman I have the email field filled out in the body, yet I still get the error missing 1 required positional argument: 'email'.
models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
from django.utils.translation import gettext_lazy as _
class CustomAccounManager(BaseUserManager):
def create_superuser(self, email, username, password, **other_fields):
other_fields.setdefault('is_staff', True)
other_fields.setdefault('is_superuser', True)
other_fields.setdefault('is_active', True)
return self.create_user(self, email, username, password, **other_fields)
def create_user(self, email, username, password, **other_fields):
if not email:
raise ValueError(_('You must provide an email address'))
email = self.normalize_email(email)
user = self.model(email=email, username=username, **other_fields)
user.set_password(password)
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
username = models.CharField(max_length=150, unique = True)
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
objects = CustomAccounManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
def __str__(self):
return self.username
serializers.py
from rest_framework import serializers
from rest_framework.authtoken.models import Token
from .models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'password')
extra_kwargs = {'password': {'write_only': True, 'required': False}}
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
Token.objects.create(user=user)
return user
views.py
from rest_framework import viewsets
from django.shortcuts import render
from .models import User
from .serializers import UserSerializer
class UserViewSet(viewsets.ModelViewSet):
queryset =User.objects.all()
serializer_class = UserSerializer
Any help is appreciated!
This is because you are making USERNAME_FIELD = 'email' in your custom user model, so you have to set USERNAME_FIELD = 'username' and in the email field, set
email = models.EmailField(_('email address'), null=True, blank=True)
but if you need the USERNAME_FIELD = 'email' you have to send it with other data, it's based on your case.
When I try to create a new user through DRF, the avatar field displays the default image even if the user uploads an image. When I try to create a user with an image through the admin panel it works fine. So I'm assuming that I'm missing something in my serializer.
Custom User Model
class myAccountManager(BaseUserManager):
def create_user(self, email, username, password=None):
if not email:
raise ValueError('Users must have an email')
if not username:
raise ValueError('Users must have an username')
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, email, username, password):
user = self.create_user(
email = self.normalize_email(email),
password=password,
username=username,
)
user.is_admin=True
user.is_staff=True
user.is_superuser=True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
email = models.EmailField(verbose_name="email", max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
avatar = models.ImageField(default='default.jpg')
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last login', auto_now_add=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)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = myAccountManager()
def __str__(self):
return self.username
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
User serializer
UserModel = User
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
def create(self, validated_data):
user = UserModel.objects.create_user(
username=validated_data['username'],
password=validated_data['password'],
email=validated_data['email'],
)
return user
class Meta:
model = UserModel
# Tuple of serialized model fields (see link [2])
fields = ( "id", "email", "username", "password", "avatar")
Static file path
STATIC_URL = '/static/'
MEDIA_URL = '/images/'
STATICFILES_DIRS = [
BASE_DIR / 'static'
]
MEDIA_ROOT = BASE_DIR /'static/images'
The issue is with the serializer's create() method. You were not passing the avatar data into the create_user(...) method. So, update your method as below,
from rest_framework import serializers
UserModel = User
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
def create(self, validated_data):
return UserModel.objects.create_user(**validated_data)
class Meta:
model = UserModel
# Tuple of serialized model fields (see link [2])
fields = ("id", "email", "username", "password", "avatar")
I'm using Django REST with the rest_auth package, and I'm having an issue with serializing custom fields when registering a new user.
The field "is_employer" is always set to false even when you set it to true. Also in the API if you set the is_employer checkbox to true, it doesn't change anything. I added it in models, serializers and adapter, what am I missing?
MODELS:
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=self.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=self.normalize_email(email),
password=password,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class CustomUser(AbstractBaseUser):
username = None
first_name = None
last_name = None
email = models.EmailField(verbose_name='email address', max_length=255, 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)
is_employer = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = MyUserManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(selfself, app_label):
return True;
SERIALIZERS:
from django.contrib.auth.hashers import make_password
from rest_framework import serializers
from rest_auth.registration.serializers import RegisterSerializer
from users.models import CustomUser
class CustomRegisterSerializer(RegisterSerializer):
def get_cleaned_data(self):
data_dict = super().get_cleaned_data()
data_dict['is_employer'] = self.validated_data.get('is_employer', '')
return data_dict
ADAPTER:
class CustomAccountAdapter(DefaultAccountAdapter):
def save_user(self, request, user, form, commit=False):
user = super().save_user(request, user, form, commit)
data = form.cleaned_data
user.is_employer = data.get('is_employer')
user.save()
return user
First, set the is_employer field explicitly in the CustomRegisterSerializer class
from rest_auth.registration.serializers import RegisterSerializer
class CustomRegisterSerializer(RegisterSerializer):
is_employer = serializers.BooleanField(default=True)
def get_cleaned_data(self):
data_dict = super().get_cleaned_data()
data_dict['is_employer'] = self.validated_data.get('is_employer', False)
return data_dict
then in your settings.py update the serializer as
# settings.py
REST_AUTH_REGISTER_SERIALIZERS = {
"REGISTER_SERIALIZER": "dotted.path.to.CustomRegisterSerializer"
}
I want to implement update User Profile,in django rest framework.
I am getting the above mentioned error, no matter what I try and change in my code.
Below is the the code for my user serializers, user model and api views.
users/api/serializers.py:
from rest_framework import serializers
from ..models import User,Profile
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username','first_name','last_name','phone','id')
class UserProfileSerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=True)
class Meta:
model = Profile
fields = ('user', 'bio', 'image')
def update(self,instance,validated_data):
user_data = validated_data.pop('user',{})
user = instance.user
instance.bio = validated_data.get('bio',instance.bio)
instance.image = validated_data.get('image',instance.image)
instance.save()
return instance
Is there anything wrong in my serializer, cause I tried hardcoding and saving a particular user profile also by using for ex: instance.user.id = 21 and then saving it, but i get the same error
Is there anything wrong in my serializer, cause I tried hardcoding and saving a particular user profile also by using for ex: instance.user.id = 21 and then saving it, but i get the same error
users/models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.conf import settings
import os
import random
import string
class MyAccountManager(BaseUserManager):
def create_user(self,phone,username,first_name,last_name):
if not phone:
raise ValueError("Users must have a valid phone number")
if not username:
raise ValueError("Users must have a valid username")
if not first_name:
raise ValueError("Users must have a valid First Name")
if not last_name:
raise ValueError("Users must have a valid last name")
user = self.model(
phone=phone,
username=username,
first_name=first_name,
last_name=last_name
)
user.save(using=self._db)
return user
def create_superuser(self,username,phone,first_name,last_name,password = None):
user = self.create_user(
username=username,
phone=phone,
first_name=first_name,
last_name=last_name,
)
user.set_password(password)
user.is_admin=True
user.is_staff=True
user.is_superuser=True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
phone = models.CharField(unique=True,max_length=20)
username = models.CharField(max_length=50,unique=True)
first_name = models.CharField(max_length=40)
last_name = models.CharField(max_length=30, blank=True)
date_joined = models.DateTimeField(verbose_name='date_joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last_login', auto_now_add=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)
otp = models.CharField(max_length=10,default='')
USERNAME_FIELD = 'phone'
REQUIRED_FIELDS = ['username','first_name','last_name']
objects = MyAccountManager()
def __str__(self):
return self.username
def has_perm(self,perm,obj = None):
return self.is_admin
def has_module_perms(self,app_label):
return True
class Profile(models.Model):
user = models.OneToOneField(User,on_delete = models.CASCADE)
bio = models.CharField(max_length=140)
image = models.ImageField(default='default.jpg',upload_to='profile_pics')
def __str__(self):
return f'{self.user.username}'
users/api/views.py
from rest_framework import status
from rest_framework.response import Response
from rest_framework import viewsets
from rest_framework.views import APIView
from .serializers import UserSerializer,UserProfileSerializer
from ..models import User,Profile
from django_filters.rest_framework import DjangoFilterBackend
class ProfileViewset(viewsets.ModelViewSet):
model = Profile
serializer_class = UserProfileSerializer
queryset = Profile.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ['user']
Please add null=True if you want to insert null value.This is my suggestion
class Profile(models.Model):
user = models.OneToOneField(User,null=True,on_delete = models.CASCADE)
bio = models.CharField(max_length=140)
image = models.ImageField(default='default.jpg',upload_to='profile_pics')
def __str__(self):
return f'{self.user.username}'
I am implementing user authentication with django-rest_framework_simple-jwt with custom user,
My models.py:
class UserManager(BaseUserManager):
def create_user(self, email, username, password, alias=None):
user = self.model(
email = self.normalize_email(email),
username = username,)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, username, password):
self.create_user(email, username, password)
user.is_staff()
user.is_superuser = True
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(null=False, unique=True)
username = models.CharField(max_length=25, unique=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username",]
So I am implementing restframework simple-jwt authentication,my settings .py is as follows as:
REST_FRAMEWORK={
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
]}
my urls.py:
urlpatterns = [
url(r'^api/token/$', TokenObtainPairView.as_view(), name='token_obtain_pair'),
url(r'^api/token/refresh/$', TokenRefreshView.as_view(), name='token_refresh'),]
on login process, it returns error that "detail": "No active account found with the given credentials" all my users were active. I have no clue to sort this out, I need help.Thanks in advance.
Ensure your password is being hashed before it is stored in your db. I ran into the same problem and discovered my passwords were being stored in plain text. Adding the following to my UserSerializer solved the issue
from django.contrib.auth.hashers import make_password
def validate_password(self, value: str) -> str:
"""
Hash value passed by user.
:param value: password of a user
:return: a hashed version of the password
"""
return make_password(value)
Either you did not create a superuser for your Django application or you are provided the wrong credentials for authentication
Did you remember to set in settings:
AUTH_USER_MODEL = 'your_app_name.User'
Also make sure, is_active = True for the user object that you are saving in your serializer, because
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['fullname', 'username', 'email', 'password']
def create(self, validated_data):
password = validated_data.pop('password', None)
instance = self.Meta.model(**validated_data)
# Adding the below line made it work for me.
instance.is_active = True
if password is not None:
# Set password does the hash, so you don't need to call make_password
instance.set_password(password)
instance.save()
return instance
Note ( As per docs )
The login_required decorator does NOT check the is_active flag on a user, but the default AUTHENTICATION_BACKENDS reject inactive users.
It seems my error was being caused by a write_only parameter on my password field
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(
max_length=68, min_length=6, write_only=True)
class Meta:
model = User
fields = ['email', 'username', 'password']
Removed it:
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(
max_length=68, min_length=6)
class Meta:
model = User
fields = ['email', 'username', 'password']
and then it was all sunshine and rainbows after that :-)
try this
from django.contrib.auth.hashers import make_password
class UserManager(BaseUserManager):
def create_user(self, email, username, password, alias=None):
user = self.model(
email = self.normalize_email(email),
username = username,)
user.set_password(make_password(password))
user.save()
return user
def create_superuser(self, email, username, password):
self.create_user(email, username, password)
user.is_staff()
user.is_superuser = True
user.save()
return user
Downgraded manually from PyJWT==2.0.0 to PyJWT==1.7.1 and solved our problem
pip install PyJWT==1.7.1
We are using djangorestframework==3.12.1 and djangorestframework-simplejwt==4.4.0 on our requirements.txt and that gave us automatically the 2.0.0 version dependency.
In my opinion, there is a problem where an email address and username is provided for the serializer, but an email is expected as a username for authentication.
I had the same error too. I also made some kind of custom user and tried to login to get a couple of json web tokens. But I only used email, not username. So what I did in the end and it works for me. Perhaps this example explains something in the place where authentication is done ...
Model and manager like this:
from django.db import models
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import (
AbstractBaseUser,
BaseUserManager
)
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist
from rest_framework_simplejwt.tokens import RefreshToken
class CustomUserManager(BaseUserManager):
def get_or_create(self, email=None, **kwargs):
allowed_kwargs = ['first_name', 'last_name', 'img', 'about']
if email is not None:
try:
user_obj = super(CustomUserManager, self).get(email=email)
if kwargs:
for k, v in kwargs.items():
setattr(user_obj, k, v)
user_obj.save()
except ObjectDoesNotExist:
email = self.normalize_email(email)
user_obj = self.model(email=email)
password = kwargs.pop('password', None)
if password is not None:
user_obj.set_password(password)
if kwargs:
for k, v in kwargs.items():
if k in allowed_kwargs:
setattr(user_obj, k, v)
user_obj.save()
else:
return False
return user_obj
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), null=True, unique=True)
first_name = models.CharField(max_length=150, null=True, blank=True)
last_name = models.CharField(max_length=150, null=True, blank=True)
img = models.URLField(null=True, blank=True)
about = models.TextField(_('about'), max_length=500, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
objects = CustomUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
def __str__(self):
return f'<CustomUser(id={self.id} - email={self.email})>'
class Meta:
ordering = ['-created_at']
#property
def full_name(self):
if hasattr(self, 'first_name') and hasattr(self, 'last_name'):
return f'{self.first_name} {self.last_name}'
return 'No fullname'
#property
def jwt_tokens(self):
refresh = RefreshToken.for_user(self)
return {
'refresh': str(refresh),
'access': str(refresh.access_token),
}
Customizing token serializer:
from django.contrib.auth import authenticate
from django.contrib.auth.models import update_last_login
from django.core.exceptions import ObjectDoesNotExist
from rest_framework import serializers
class CustomTokenSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
email = serializers.EmailField(required=True)
password = serializers.CharField(min_length=8, write_only=True)
def validate(self, email, password):
try:
self.user = CustomUser.objects.get(email=email)
except ObjectDoesNotExist as e:
message = {'error': f'User with email={email} does not exist.'}
return message
check_auth = authenticate(username=email, password=password)
if check_auth is None:
message = {'error':
'The user exists, but the password is incorrect.'}
return message
data = self.user.jwt_tokens
update_last_login(None, self.user)
return data
Urls:
urlpatterns += [
path('login/token/', views.LoginTokenView.as_view(), name='login-token')
]
I faced a similar issue. Turns out that I had not included the password field among the fields in the Writer serializer.
Before I had code like this;
class UserWriterSerializer(serializers.ModelSerializer):
class Meta:
model = AppUser
fields = [
'id',
'username',
'first_name',
'last_name',
'email',
'is_active',
'telephone',
'userType',
'gender',
'registration_date'
]
Then I added the password field to have this;
class UserWriterSerializer(serializers.ModelSerializer):
class Meta:
model = AppUser
fields = [
'id',
'username',
'password',
'first_name',
'last_name',
'email',
'is_active',
'telephone',
'userType',
'gender',
'registration_date'
]
So in summary, some different value was being saved in the database which was not the password I added. Thus having that error, because the password you place as an input is not matching with what is in the database. Make sure that the serializer is correct