I am trying to display the fields of my user model but I always get that my serializer is not valid
{
"non_field_errors": [
"Invalid data. Expected a dictionary, but got User."
]
}
this is my model
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, PermissionsMixin
class UserManager(BaseUserManager):
def _create_user(self, username, password, is_staff, is_superuser, **extra_fields):
user = self.model(
username=username,
is_staff=is_staff,
is_superuser=is_superuser,
**extra_fields
)
user.set_password(password)
user.save(using=self.db)
return user
def create_user(self, username, password=None, **extra_fields):
return self._create_user(username, password, False, False, **extra_fields)
def create_superuser(self, username, password=None, **extra_fields):
return self._create_user(username, password, True, True, **extra_fields)
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=255, unique=True)
email = models.EmailField( max_length=255, blank=True, null=True)
name = models.CharField(max_length=255, blank=True, null=True)
age = models.PositiveIntegerField()
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = []
def __str__(self):
return f"{self.id} {self.name} {self.username} {self.age}"
this is my serializer
class UserUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'email', 'username', 'name', 'age']
this is my view
class UserUpdateApiView(APIView):
def get(self, request, pk):
try:
queryset = User.objects.get(pk=pk)
serializer = UserUpdateSerializer(data=queryset)
if serializer.is_valid(raise_exception=True):
return Response(data=serializer.data)
except User.DoesNotExist:
return Response(data={"error": "User no found"}, status=status.HTTP_404_NOT_FOUND)
You have used the data keyword argument, i think the problem is here. Pass the queryset without keyword argument:
class UserUpdateApiView(APIView):
def get(self, request, pk):
try:
queryset = User.objects.get(pk=pk)
serializer = UserUpdateSerializer(queryset)
return Response(serializer.data)
except User.DoesNotExist:
return Response(data={"error": "User no found"}, status=status.HTTP_404_NOT_FOUND)
data is the serialized output in fact. the keyword argument for passing your input model data is named instance I believe
Related
I used Django restframework.
To implement customize user model, I use AbstractBaseUser.
models.py code is below.
[models.py]
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.utils import timezone
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, username, email, password, is_staff, is_admin, is_active, is_superuser, **extra_fields):
now = timezone.now()
if not username:
raise ValueError('Username must be set')
email = self.normalize_email(email)
user = self.model(username=username, email=email,
is_staff=is_staff, is_admin=is_admin,
is_active=is_active, is_superuser=is_superuser,
date_joined=now, **extra_fields)
user.set_password(password)
user.save(self._db)
return user
def create_user(self, username, email, password, **extra_fields):
return self._create_user(username, email, password, False, False, True, False, **extra_fields)
def create_superuser(self, username, email, password, **extra_fields):
return self._create_user(username, email, password, True, True, True, True, **extra_fields)
class User(AbstractBaseUser):
USER_TYPE_CHOICES = (
('django', 'Django'),
('facebook', 'Facebook'),
('google', 'Google')
)
user_type = models.CharField(
max_length=20,
choices=USER_TYPE_CHOICES,
default='Django'
)
email = models.CharField(max_length=100, null=False)
username = models.CharField(max_length=20, unique=True)
phone = models.CharField(max_length=12)
# Default Permission
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'username'
objects = UserManager()
REQUIRED_FIELDS = ['email']
def get_full_name(self):
pass
def get_short_name(self):
pass
#property
def is_superuser(self):
return self.is_admin
#property
def is_staff(self):
return self.is_admin
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return self.is_admin
#is_staff.setter
def is_staff(self, value):
self._is_staff = value
When I create super user,
It throws TypeError: 'is_superuser' is an invalid keyword argument for this function
Maybe I think there is no function related is_superuser in my code, but I don't know exactly what I have to do.
Is there any solution about this?
Thanks.
Looks like is_superuser field overrided by property with same name. You should rename is_superuser property to fix error:
#property
def is_superuser_property(self):
return self.is_admin
When I create a new user, his password remains unencrypted in the database.
Here is my models.py file:
from django.contrib.auth.models import AbstractBaseUser
from django.db import models
from .managers import UserManager
class UserProfile(AbstractBaseUser):
phone = models.CharField(max_length=100, unique=True, db_index=True, primary_key=True)
objects = UserManager()
USERNAME_FIELD = 'phone'
REQUIRED_FIELDS = []
class Meta:
verbose_name = 'user'
verbose_name_plural = 'users'
def get_full_name(self):
return self.phone
def get_short_name(self):
return self.phone
serializers.py:
class UserProfileSerializer(serializers.ModelSerializer):
phone = serializers.CharField(required=True, allow_blank=False)
password = serializers.CharField(required=True, allow_blank=False, write_only=True)
class Meta:
model = UserProfile
fields = '__all__'
extra_kwargs = {'password': {'write_only': True}}
views.py:
class UserProfileViewSet(ModelViewSet):
serializer_class = UserProfileSerializer
queryset = UserProfile.objects.all()
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(data=serializer.data, status=HTTP_200_OK)
managers.py:
from django.contrib.auth.models import BaseUserManager
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, phone, password, **extra_fields):
if not phone or not password:
raise ValueError('Err!')
user = self.model(phone=phone, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, phone, password, **extra_fields):
extra_fields.setdefault('is_superuser', False)
return self._create_user(phone, password, **extra_fields)
def create_superuser(self, phone, 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(phone, password, **extra_fields)
in settings.py i have wrote that:
AUTH_USER_MODEL = 'users.UserProfile'
Using print, I found out that no UserManager methods are used when creating a user. What am I doing wrong?
You are answering your own question: you are not using the manager methods to create the user, you are just saving the data. Implement UserProfileSerializer.save and call User.objects.create_user there instead of using ModelSerializer.save (it doesn’t know that your model is a user model).
In the serializers.py write the create method:
class UserProfileSerializer(serializers.ModelSerializer):
phone = serializers.CharField(required=True, allow_blank=False)
password = serializers.CharField(required=True, allow_blank=False, write_only=True)
class Meta:
model = UserProfile
fields = '__all__'
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
return UserProfile.objects.create_user(**validated_data)
Reference:
https://www.django-rest-framework.org/api-guide/serializers/#saving-instances
I have customized user model by extending AbstractBaseUser, the user name only accepted as email id. Here is the model:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField('email address', unique=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)
is_staff = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
verbose_name = 'user'
verbose_name_plural = 'users'
def get_full_name(self):
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
return self.first_name
def email_user(self, subject, message, from_email=None, **kwargs):
send_mail(subject, message, from_email, [self.email], **kwargs)
The model manager for the above model is:
class UserManager(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)
I am able to create the custom user but when I am trying to log in I got the attribute error:
Attribute error: 'User' object has no attribute 'is_admin'
Below is the admin.py file
class ProfileInline(admin.StackedInline):
model = Course
can_delete = False
verbose_name_plural = 'Course'
fk_name = 'user'
class CustomUserAdmin(UserAdmin):
inlines = (ProfileInline, )
def get_inline_instances(self, request, obj=None):
if not obj:
return list()
return super(CustomUserAdmin, self).get_inline_instances(request, obj)
admin.site.register(User, CustomUserAdmin)
Django user models don't have the attribute is_admin.
The error is shown because somewhere in your code (probably login view?) you are calling user.is_admin. Find it and remove it, or use user.is_staff / user.is_superuser instead.
I'm having trouble while sending PUT request for my custom user model
On sending PUT request to /api/provider/1/, where 1 is pk, with put data phone_number = 1234567890 I get {"email": ["This field is required."] }
If I send email and phone_number, I get {"email": ["Provider with this email already exists."]}
Model
class ProviderManager(BaseUserManager):
def _create_user(self, email, password, is_staff, is_superuser, **extra_fields):
'''Creates and saves a User with the given email and password'''
now = timezone.now()
if not email:
raise ValueError('Email can\'t be empty')
email = self.normalize_email(email)
user = self.model(email=email, is_active=True, is_superuser=is_superuser,
is_staff=is_staff, last_login=now, date_joined=now,
**extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password, phone_number, **extra_fields):
extra_fields['phone_number'] = phone_number
return self._create_user(email, password, False, False, **extra_fields)
def create_user(self, email, password, phone_number, **extra_fields):
extra_fields['phone_number'] = phone_number
return self._create_user(email, password, True, True, **extra_fields)
class Provider(AbstractBaseUser):
name = models.CharField(max_length=256, default='')
email = models.EmailField(max_length=256, unique=True, db_index=True)
phone_number = models.CharField(max_length=32, unique=True)
language = models.CharField(max_length=8, default='')
currency = models.CharField(max_length=8, default='')
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['phone_number',]
objects = ProviderManager()
class Meta:
verbose_name = 'user'
verbose_name_plural = 'users'
def __unicode__(self):
return self.email
def get_full_name(self):
return self.name
def get_short_name(self):
return self.name
def email_user(self, subject, message, from_email=None, **kwargs):
send_mail(subject, message, from_email, [self.email])
Serializer
class ProviderSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ('id', 'name', 'email', 'phone_number', 'language', 'currency',)
View
#api_view(['GET', 'PUT', 'DELETE'])
def provider_detail(request, provider_id):
'''Read, update or delete a provider'''
try:
provider = User.objects.get(pk=provider_id)
except User.DoesNotExist:
return Response(status=HTTP_404_NOT_FOUND)
print('GOT PROVIDER ' + provider.email)
if request.method == 'GET':
serializer = ProviderSerializer(provider)
return Response(serializer.data)
elif request.method == 'PUT':
serializer = ProviderSerializer(provider, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
provider.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
When doing a PUT you need to submit all the fields for the model only a PATCH would allow you to update by passing one field
There is partial parameter which you can pass to serializer, to indicate, that it is a partial update.
From the doc:
http://www.django-rest-framework.org/api-guide/serializers/#partial-updates
lets have a structure of my User model.
BaseUser <- BusinessOwner <- Business Staff (BusinessOwner can create,update,delete BusinessStaff )
BaseUser <- Customer
I'm having problem when creating an inherited user from AbstractBaseUser, All i want is to add a row in myappname_baseuser_user_permissions table which has columns : id , baseuser_id, permission_id, with correct permissions assign to correct user id, such as : add_staff, change_staff, delete_staff
Things is normal when i create new BusinessOwner user with admin page and easily add permissions, but not the POST method im using with django restframework, there are no permissions. So where should i put my permissions code? and what is the code? in model.py or view.py ? ,my permissions codename are : add_staff, change_staff, and delete_staff
here is my model.py:
class UserManager(BaseUserManager):
def _create_user(self, email, password, is_staff, is_superuser, **extra_fields):
now = timezone.now()
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
user = self.model(email=email,
is_staff=is_staff, is_active=True,
is_superuser=is_superuser, last_login=now,
date_joined=now, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra_fields):
return self._create_user(email, password, False, False,
**extra_fields)
def create_superuser(self, email, password, **extra_fields):
return self._create_user(email, password, True, True,
**extra_fields)
class BaseUser(AbstractBaseUser, PermissionsMixin):
first_name=models.CharField(max_length=20)
last_name=models.CharField(max_length=20)
email=models.EmailField(max_length=254, unique=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
class BusinessOwner(BaseUser):
business_name=models.CharField(max_length=20)
class Customer(BaseUser):
address=models.CharField(max_length=30)
class Staff(BaseUser):
position=models.CharField(max_length=30)
my view.py
class CreateBusinessOwnerView(mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
queryset = BusinessOwner.objects.all()
serializer_class = CreateBusinessOwner
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
def post_save(self, obj, created=False):
if created:
obj.set_password(obj.password)
obj.save()
and my serializers.py
class CreateBusinessOwner(serializers.ModelSerializer):
class Meta:
model = BusinessOwner
fields = ('email', 'password', 'first_name', 'last_name', 'business_name' ,'date_joined')
read_only_fields = ('date_joined',)
Thanks for helping me!