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
Related
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
I am working with AbstractBase user. I have created users and groups. After I assign group to user, if I login with that user , the user has access to the complete admin site with all the CRUD operations.
I have a created a product group with add-delete-edit-view permissions(default) and assigned a user to it. But when this user logins to the admin site, he has access to all the other items of the site as well.
How do I make sure the logged in user can access only the items from assigned groups /permissions???
#managers.py
from django.contrib.auth.base_user import BaseUserManager
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)
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_active', True)
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)
extra_fields.setdefault('is_active', 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)
#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 UserManager
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_superuser = models.BooleanField(_('is_superuser'), default=True)
is_staff= models.BooleanField(_('is_staff'), default=True)
objects = UserManager()
USERNAME_FIELD = 'email'
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 email_user(self, subject, message, from_email=None, **kwargs):
'''
Sends an email to this User.
'''
send_mail(subject, message, from_email, [self.email], **kwargs)
#forms.py
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from .models import User
class RegisterForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email',)
def clean_email(self):
email = self.cleaned_data.get('email')
qs = User.objects.filter(email=email)
if qs.exists():
raise forms.ValidationError("email is taken")
return email
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
class UserAdminCreationForm(forms.ModelForm):
"""
A form for creating new users. Includes all the required
fields, plus a repeated password.
"""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email',)
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserAdminChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = User
fields = ('email', 'password', 'is_active','is_superuser','is_staff')
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
#admin.py
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .forms import UserAdminCreationForm, UserAdminChangeForm
from .models import User
class UserAdmin(BaseUserAdmin):
# The forms to add and change user instances
form = UserAdminChangeForm
add_form = UserAdminCreationForm
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = ('email', 'is_superuser')
list_filter = ('is_superuser',)
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ()}),
('Permissions', {'fields': ('is_superuser','groups')}),
)
# 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': ('email', 'password1', 'password2')}
),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()
admin.site.register(User, UserAdmin)
typo : password instead of password1
class RegisterForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput)
and you are also missing this methods in you User Model:
def has_perm(self, perm, obj=None):
return True # self.is_admin
def has_module_perms(self, app_label):
return True
I want to create a custom Signup form with Django Rest Auth and Django Allauth but I'm getting an error save() takes 1 positional argument but 2 were given
I know that this error is related to the function def save(self, request) provided by Django Rest Auth, but I have no clue how I can change it.
What should I do to make it work?
Bellow is the respective code for my user Model and Serializer:
# Models.py
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, **extra_fields):
"""Creates and saves a new super user"""
user = self.create_user(email, password, **extra_fields)
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
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)
age = models.PositiveIntegerField(null=True, blank=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name', 'age']
def __str__(self):
return self.email
# serializers.py
class UserSerializer(serializers.ModelSerializer):
"""Serializer for the users object"""
class Meta:
model = get_user_model()
fields = ('email', 'password', 'name', 'age')
extra_kwargs = {'password': {'write_only': True, 'min_length': 5}}
def create(self, validated_data):
"""Create a new user with encrypted password and return it"""
return get_user_model().objects.create_user(**validated_data)
def update(self, instance, validated_data):
"""Update a user, setting the password correctly and return it"""
password = validated_data.pop('password', None)
user = super().update(instance, **validated_data)
if password:
user.set_password(password)
user.save()
return user
def save(self, request):
# I would say that I need to change the default function
# settings. py
REST_AUTH_REGISTER_SERIALIZERS = {
'REGISTER_SERIALIZER': 'user.serializers.UserSerializer'
}
In order to get this fixed I just add the following to my serializer:
class UserSerializer(serializers.ModelSerializer):
"""Serializer for the users object"""
class Meta:
model = get_user_model()
fields = ('email', 'password', 'name', 'age')
extra_kwargs = {'password': {'write_only': True, 'min_length': 5}}
def create(self, validated_data):
"""Create a new user with encrypted password and return it"""
return get_user_model().objects.create_user(**validated_data)
def update(self, instance, validated_data):
"""Update a user, setting the password correctly and return it"""
password = validated_data.pop('password', None)
user = super().update(instance, **validated_data)
if password:
user.set_password(password)
user.save()
return user
def get_cleaned_data(self):
return {
'password': self.validated_data.get('password', ''),
'email': self.validated_data.get('email', ''),
'name': self.validated_data.get('name', ''),
'age': self.validated_data.get('age', ''),
}
def save(self, request):
self.cleaned_data = self.get_cleaned_data()
user = get_user_model().objects.create_user(**self.cleaned_data)
return user
I want to be able to attach a user to a group upon creation.
Here is the result of select * from auth_group:
Here is the my serializer.py file:
from rest_framework import serializers
from .models import User
class UserSerializer(serializers.ModelSerializer):
class Meta(object):
model = User
fields = ('id', 'email', 'first_name', 'last_name', 'phone', 'address', 'is_active', 'is_staff',
'is_superuser', 'date_joined', 'password',)
extra_kwargs = {'password': {'write_only': True}}
Here is my model.py file:
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
from django.contrib.auth.models import PermissionsMixin, UserManager, Group
from django.db import models, transaction
# Create your models here.
from django.utils import timezone
class UserManager(BaseUserManager):
def _create_user(self, email, password, **extra_fields):
"""
Creates and saves a User with the given email,and password.
"""
if not email:
raise ValueError('User must have an email address')
email = self.normalize_email(email)
if not extra_fields["group_id"]:
raise ValueError('User must have group id')
try:
with transaction.atomic():
user = self.model(email=email, **extra_fields)
group = Group.objects.get(extra_fields["group_id"])
group.user_set.add(user)
user.set_password(password)
user.save(using=self._db)
return user
except:
raise
def create_user(self, email, password=None, **extra_fields):
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, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
return self._create_user(email, password=password, **extra_fields)
class User(AbstractBaseUser, PermissionsMixin):
"""
An abstract base class implementing a fully featured User model with
admin-compliant permissions.
"""
email = models.EmailField(max_length=40, unique=True)
first_name = models.CharField(max_length=30, blank=True)
last_name = models.CharField(max_length=30, blank=True)
phone = models.CharField(max_length=20, blank=True)
address = models.CharField(max_length=30, blank=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
date_joined = models.DateTimeField(default=timezone.now)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'phone']
def get_full_name(self):
"""" Used to display user's full name """
return "{}, {}".format(self.first_name, self.last_name)
def __srt__(self):
return self.email
def save(self, *args, **kwargs):
super(User, self).save(*args, **kwargs)
return self
And finally, here is my view.py:
class CreateUserAPIView(APIView):
# Allow any user (authenticated or not) to access this url
permission_classes = (AllowAny,)
def post(self, request):
user = request.data
serializer = UserSerializer(data=user)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response({"user": serializer.data, "status": status.HTTP_200_OK})
I want for this request:
{
"email": "myemail#gmail.com",
"first_name": "myfirst_name",
"last_name": "mylast_name",
"phone": "000556660",
"address": "myaddress",
"password": "mypassword",
"group_id": 5
}
To get this response:
{
"status": 200,
user: {
"email": "myemail#gmail.com",
"first_name": "myfirst_name",
"last_name": "mylast_name",
"phone": "000556660",
"address": "myaddress",
"password": "mypassword",
"groups": [5]
}
}
I have followed this link Adding a user to a group in django but it's not helping me.
Thanks, any help would be appreciated.
Try this :
class UserSerializers(serializers.ModelSerializer):
# groups = GroupSerializer(many=True)
class Meta:
model = User
fields = ('id', 'email', 'first_name', 'last_name', 'phone', 'address', 'is_active', 'is_staff',
'is_superuser', 'date_joined', 'password', 'groups')
def create(self, validated_data):
groups_data = validated_data.pop('groups')
user = User.objects.create(**validated_data)
for group_data in groups_data:
# Group.objects.create(user=user, **group_data)
user.groups.add(group_data)
return user
Edit: Because User and Group are in many-to-many relations so you can directly add the group field in the users serializers. For more details follow django.contrib.auth.models package and User inherits AbstactUser and AbstractUser inherits PermissionsMixin which has groups as many to many field.
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!