How to eliminate username from authentication - python

I want to eliminate the concept of a username from the django auth in my app. I want the email of the user to take place of the username. So I extended AbstractBaseUser with the code below
class AuthUserManager(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.is_active = True
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password):
user = self.create_user(email=email, password=password)
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class AuthUser(AbstractBaseUser, PermissionsMixin):
alphanumeric = RegexValidator(r'^[0-9a-zA-Z]*$', message = "Only alphanumeric characters are allowed")
email = models.EmailField(verbose_name='email address',unique=True, max_length=255)
first_name = models.CharField(unique=True, max_length=20, validators=[alphanumeric])
last_name = models.CharField(unique=True, max_length=20, validators=[alphanumeric])
date_joined = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True, null=False)
is_staff = models.BooleanField(default=False, null=False)
#custom fields
company_name = models.CharField(max_length=100)
telephone_number = models.CharField(max_length=100)
website_url = models.CharField(max_length=100)
objects = AuthUserManager()
USERNAME_FIELD = 'email'
#REQUIRED_FIELDS = ['first_name']
def get_full_name(self):
fullname = self.first_name + self.last_name
return fullname
def get_short_name(self):
return self.email
def __unicode__(self):
return self.email
In my serializers.py I have this
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = AuthUser
fields = ('email', 'first_name', 'last_name')
def create(self, validated_data):
user = AuthUser.objects.create(**validated_data)
return user
def update(self, instance, validated_data):
instance.email = validated_data.get('email', instance.email)
instance.first_name = validated_data.get('first_name', instance.first_name)
instance.last_name = validated_data.get('last_name', instance.last_name)
instance.save()
return instance
But when I try to register I get the following error:
{
"username": [
"This field is required."
]
}
What am I doing wrong?

In your serializer, you need to exclude username field, because you are inheriting from AbstractBaseUser and you still have 'username' field, so add this exclude = ('username',)
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = AuthUser
fields = ('email', 'first_name', 'last_name')
exclude = ('username',)
def create(self, validated_data):
user = AuthUser.objects.create(**validated_data)
return user

Related

incorrect username and password error in web application made in Django

for my web-application which is made in Django and I made a custom users app for users (so I am not using the Django's user). I managed to get the users app working and I created a superuser using this command:
python manage.py createsuperuser
and got this message:
Superuser created successfully.
but when I tried to log in as the superuser in the browser, it did not work and got this error message on the browser (I tried different browsers as well):
Please enter the correct username and password for a staff account. Note that both fields may be case-sensitive.
I paid attention to case-sensitive letters. do you know what the problem could be?
here is the models.py for the users app:
import random
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.core import validators
from django.utils import timezone
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager, send_mail
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, username, password, phone_number, email, is_staff, is_superuser, **extra_fields):
"""
Created and saves a User with the given username, email and password.
"""
now = timezone.now()
if not username:
raise ValueError('The given username must be set')
email = self.normalize_email(email)
user = self.model(phone_number=phone_number,
username=username, email=email,
is_staff=is_staff, is_active=True,
is_superuser=is_superuser,
date_joined=now, **extra_fields)
if not extra_fields.get('no_password'):
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, username=None, phone_number=None, email=None, password=None, **extra_fields):
if username is None:
if email:
username = email.split('#', 1)[0]
if phone_number:
username = random.choice('abcdefghijklmnopqrstuvwxyz') + str(phone_number)[-7:]
while User.objects.filter(username=username).exists():
username += str(random.randint(10, 99))
return self._create_user(username, phone_number, email, password, False, False, **extra_fields)
def create_superuser(self, username, email, phone_number, password, **extra_fields):
return self._create_user(username, email, phone_number, password, True, True, **extra_fields)
def get_by_phone_number(self, phone_number):
return self.get(**{'phone_number': phone_number})
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(_('username'), max_length=32, unique=True,
help_text=
'Required. 30 characters or fewer starting with a letter. Letters, digits',
validators=[
validators.RegexValidator(r'^[a-zA-Z][a-zA-Z0-9_\.]+$',
_('Enter a valid username starting with a-z.'
'This value may contain only letters and numbers'
'and underscore characters.'), 'invalid')
],
error_messages={
'unique':_('A user with that username already exists.'),
}
)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
email = models.EmailField(_('email address'), unique=False, null=True, blank=True)
phone_number = models.BigIntegerField(_('phone number'), unique=True, null=True, blank=True,
validators=[
validators.RegexValidator(r'^319[0-3,9]\d{8}$',
('Enter a valid mobile number.'), 'egrwfk')
],
error_messages={
'unique': _('A user with this mobile phone number already exits')
}
)
is_staff = models.BooleanField(_('staff status'), default=False,
help_text='designates whether this 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'))
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
last_seen = models.DateTimeField(_('last seen date'), null=True)
objects = UserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email', 'phone_number']
class Meta:
db_table = 'users'
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)
#property
def is_loggedin_user(self):
return self.phone_number is not None or self.email is not None
def save(self, *args, **kwargs):
if self.email is not None and self.email.strip() == '':
self.email = None
super().save(*args, **kwargs)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
nick_name = models.CharField(_('nick_name'), max_length=150, blank=True)
avatar = models.ImageField(_('avatar'), blank=True)
birthday = models.DateField(_('birthday'), null=True, blank=True)
gender = models.BooleanField(_('gender'), null=True, help_text='femal is False, male is True, null is unset')
province = models.ForeignKey(verbose_name=_('province'), to='Province', null=True, on_delete=models.SET_NULL)
# email = models.EmailField(_('email_address'), blank=True)
# phone_number = models.BigIntegerField(_('phone_number'), null=True, blank=True,
# validators=[
# validators=RegexValidators(r'^319[0-3,9]\d(8)$,
# _('Enter a valid mobile number'), 'invalid'),
# ],
# )
class Meta:
db_table = 'user_profiles'
verbose_name = _('profile')
verbose_name_plural = _('profiles')
#property
def get_first_name(self):
return self.user.first_name
#property
def get_last_name(self):
return self.user.last_name
def get_nick_name(self):
return self.nick_name if self.nick_name else self.user.username
class Device(models.Model):
WEB = 1
IOS = 2
ANDROID = 3
DEVICE_TYPE_CHOICES = (
(WEB, 'web'),
(IOS, 'ios'),
(ANDROID, 'android')
)
user = models.ForeignKey(User, related_name='devices', on_delete=models.CASCADE)
device_uuid = models.UUIDField(_('Device UUID'), null=True)
# notify_token = models.CharField(_('notification token'), max_length=200, blank=True,
# validators=[validators.RegexValidator(r'([a-z]|[A-z]|[0-9])\w+',
# _('Notify token is not valid'), 'invalid')]
# )
last_login = models.DateTimeField(choices=DEVICE_TYPE_CHOICES, default=ANDROID)
device_type = models.PositiveSmallIntegerField(choices=DEVICE_TYPE_CHOICES, default=ANDROID)
device_os = models.CharField(_('device os'), max_length=20, blank=True)
device_model = models.CharField(_('device model'), max_length=50, blank=True)
app_version = models.CharField(_('app version'), max_length=20, blank=True)
created_time = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'user_devices'
verbose_name = _('device')
verbose_name_plural = _('devices')
unique_together = ('user', 'device_uuid',)
class Province(models.Model):
name = models.CharField(max_length=50)
is_valid = models.BooleanField(default=True)
modified_at = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
I am also getting this message on the terminal:
[05/Jan/2023 13:38:44] "POST /admin/login/?next=/admin/ HTTP/1.1" 200 2374

django-rest-framework - How to create seperate profiles for users based on is_staff

I am working on a job portal project. I am using custom user model
class UserManager(BaseUserManager):
def create_user(self, email, name, password=None, **extra_fields):
if not email:
raise ValueError('Users must have an email address')
if not name:
raise ValueError('Users must have a name')
user = self.model(email=self.normalize_email(email), **extra_fields)
user.set_password(password)
user.name = name
user.save(using=self._db)
return user
def create_staffuser(self, email, password, name):
user = self.create_user(
email,
name,
password=password
)
user.is_staff = True
user.save(using=self._db)
return user
def create_superuser(self, name, email, password):
user = self.create_user(email, name, password=password)
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
And I have 2 separate models one for job seekers and other for employers.
class SeekerProfile(models.Model):
"""Seeker profile for job seekers"""
MALE = 'M'
FEMALE = 'F'
OTHERS = 'O'
GENDER_CHOICES = [
(MALE, 'Male'),
(FEMALE, 'Female'),
(OTHERS, 'Others'),
]
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
date_of_birth = models.DateField()
gender = models.CharField(
max_length=1,
choices=GENDER_CHOICES
)
address = models.TextField()
city = models.CharField(max_length=100)
pincode = models.CharField(max_length=50)
phone_number = models.CharField(
max_length=50, null=False, blank=False, unique=True)
disabled = models.BooleanField(default=False)
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
limit_choices_to={'is_staff': False},
on_delete=models.CASCADE
)
def __str__(self):
return self.first_name+" "+self.last_name
class BusinessStream(models.Model):
"""Business Stream dataset database"""
business_stream_name = models.CharField(max_length=50)
user = models.ForeignKey(settings.AUTH_USER_MODEL, limit_choices_to={
'is_staff': True}, on_delete=models.CASCADE)
class CompanyProfile(models.Model):
"""company profile"""
user = models.OneToOneField(settings.AUTH_USER_MODEL, limit_choices_to={
'is_staff': True}, on_delete=models.CASCADE)
company_name = models.CharField(max_length=100)
profile_description = models.TextField()
business_stream = models.ManyToManyField(
BusinessStream)
established_date = models.DateTimeField()
company_url = models.URLField()
My doubt is how to restrict one user from creating a profile on other type of user based on is_staff field in User model.
I am new to django, please help me.
views.py
class UserProfileViewSet(ModelViewSet):
queryset = SeekerProfile.objects.all()
serializer_class = serializers.ProfileSerializer
authentication_classes = (JWTAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
def get_queryset(self):
"""Return objects for the current authenticated user only"""
queryset = SeekerProfile.objects.filter(user=self.request.user)
return queryset
def perform_create(self, serializer):
return serializer.save(user=self.request.user)
serializers.py
class ProfileSerializer(serializers.ModelSerializer):
"""Serializer for user Profile"""
class Meta:
model = SeekerProfile
fields = '__all__'
read_only_fields = ('id', 'user')
This allows employer to create seeker profile.
You would have to check the role of the authenticated user in your view and proceed accordingly - s.th. like
class UserProfileViewSet(ModelViewSet):
queryset = SeekerProfile.objects.all()
serializer_class = serializers.ProfileSerializer
authentication_classes = (JWTAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
def get_queryset(self):
"""Return objects for the current authenticated user only"""
queryset = SeekerProfile.objects.filter(user=self.request.user)
return queryset
def perform_create(self, serializer):
# Check here
if self.request.user.is_staff:
# do something if requesting user is staff
else:
# do s.th. else
return serializer.save(user=self.request.user)

The field 'email' clashes with the field 'email' from model 'account.account'. Django3.2

Newbie in django here. I've been trying to create a simple site with django and I just finished creating the models. However, when I try to makemigrations,I get this:
SystemCheckError: System check identified some issues:
ERRORS:
account.Account.email: (models.E006) The field 'email' clashes with the field 'email' from model 'account.account'.
I checked my code, but i couldn't find anything bad. Maybe my eyes are broken.
Here's my models.py:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class AccountManager(BaseUserManager):
def create_user(self, first_name, last_name, name, email, password=None):
if not email:
raise ValueError("User must have an email address")
user = self.model(
email = self.normalize_email(email),
first_name = first_name,
last_name = last_name,
name = name,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, first_name, last_name, name, email, password=None):
user = self.create_user(
email = self.normalize_email(email),
password = password,
first_name = first_name,
last_name = last_name,
name = name,
)
user.is_admin = True
user.is_staff = True
user.is_active = True
user.is_superadmin = True
user.save(using=self._db)
return user
class Account(AbstractBaseUser):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField(max_length=100, unique=True)
phone_number = models.CharField(max_length=50)
name = models.CharField(max_length=50)
reputation = models.BigIntegerField(default=1)
downvote_count = models.IntegerField(default=0)
# mandatory fields
created_date = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now_add=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
is_superadmin = models.BooleanField(default=False)
USERNAME_FIELD = email
REQUIRED_FIELDS = ["name", "first_name", "last_name"]
objects = AccountManager()
def full_name(self):
return f"{self.first_name} {self.last_name}"
def __str__(self):
return self.email
def has_perm(self):
return self.is_admin
class Address(models.Model):
user = models.ForeignKey(Account, on_delete=models.CASCADE)
country = models.CharField(max_length=100)
state = models.CharField(max_length=50)
city = models.CharField(max_length=50)
zipcode4 = models.IntegerField()
line_1 = models.CharField(max_length=200)
line_2 = models.CharField(max_length=200)
whole_address = models.CharField(max_length=1024)
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now=True)
I'm not sure if you need it, but here's my admin.py:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import Account, Address
# Register your models here.
class AccountAdmin(UserAdmin):
list_display = ["email", "first_name", "last_name", "name", "last_login", "created_date", "is_active"]
list_display_links = ["email", "first_name", "last_name"]
readonly_fields = ["last_login", "created_date"]
ordering = ["-created_date"]
filter_horizontal = ()
list_filter = ()
fieldsets = ()
class AddressAdmin(admin.ModelAdmin):
list_display = ["user", "whole_address"]
filter_horizontal = ()
list_filter = ()
fieldsets = ()
admin.site.register(Account, AccountAdmin)
admin.site.register(Address, AddressAdmin)
As #Willem Van Onsem says in the comment, you should this like this:
USERNAME_FIELD = "email"
In your create_superuser function, change email = self.normalize_email(email) to email

django custom user model user creation issue: permissions not working

I'm making a custom user model in django, but somehow any new users created through the creation form is missing their assigned permissions (is_active, is_staff, is_admin), preventing them from logging in at all.
Can anyone show me where did I go wrong? Any suggestion is greatly appreciated!
Code snippets:
models.py
class MyUserManager(BaseUserManager):
use_in_migrations = True
def create_user(self, ID, name, email, privilege, password=None):
if not ID:
raise ValueError('Users must have a ID number')
user = self.model(
ID=ID,
name=name,
email=self.normalize_email(email),
privilege=privilege,
)
if self.privilege == 'Admin':
self.is_superuser = True
else:
user.is_active = True
user.is_staff = False
user.is_admin = False
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, NIP, name, email, privilege, password):
new_user = self.create_user(
ID,
name,
email,
privilege,
password=password,
)
new_user.is_superuser = True
new_user.save(using=self._db)
return new_user
class employee(AbstractBaseUser, PermissionsMixin):
ID = models.IntegerField(verbose_name="ID", unique=True)
name = models.CharField(verbose_name="Name", max_length=50, blank=True, unique=True)
email = models.EmailField(verbose_name="email", max_length=225, default='this#mail.com')
Department = models.CharField(max_length=50, choices=DEP_CHOICES, default='')
Role = models.CharField(max_length=50, choices=ROLE_CHOICES, default='')
privilege = models.CharField(max_length=10, default='User')
is_admin = models.BooleanField()
is_staff = models.BooleanField()
is_active = models.BooleanField()
forms.py
class CustomUserCreationForm(UserCreationForm):
ID = forms.CharField(max_length=50)
password = forms.CharField(widget=forms.PasswordInput)
class Meta(UserCreationForm):
model = employee
fields = "__all__"
class CustomUserChangeForm(UserChangeForm):
ID = forms.CharField(max_length=50)
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = employee
fields = "__all__"
admin.py
class UserAdmin(BaseUserAdmin):
# The forms to add and change user instances
add_form = CustomUserChangeForm
form = CustomUserChangeForm
model = employee
list_display = ('ID', 'name', 'email', 'privilege')
list_filter = ('is_admin',)
fieldsets = (
(None, {'fields': ('ID', 'password')}),
('Personal info', {'fields': ('name', 'email', 'privilege')}),
('Permissions', {'fields': ('is_admin', 'is_staff', 'is_active')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('ID', 'name', 'email')}
),
)
search_fields = ('name',)
ordering = ('ID',)
filter_horizontal = ()
views.py
def employee_list(request):
data_list = Employee.objects.order_by('NIP')
registered = False
if request.method == "POST":
if 'add_user' in request.POST:
user_form = CustomUserCreationForm(request.POST, prefix='add')
if user_form.is_valid():
new_user = user_form.save()
new_user.set_password(user.password)
new_user.save()
registered = True
return HttpResponseRedirect(reverse('employee'))
else:
user_form = CustomUserCreationForm(prefix='add')
return render(request, 'employee_list.html',
{'SignUpForm': user_form,
'registered': registered,
'Emp_list':data_list})
Instead of using 'priviledge' as a character field in the Employee model, which is very prone to error in user input, use a choice field instead.
class MyUserManager(BaseUserManager):
use_in_migrations = True
def create_user(self, name, email, privilege='member', is_admin=False, is_staff=False, password=None):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
name=name,
email=self.normalize_email(email),
privilege=privilege,
)
user.set_password(password)
user.is_active = True
user.is_staff = is_staff
user.is_admin = is_admin
user.save(using=self._db)
return user
def create_superuser(self, name, email, password):
new_user = self.create_user(
name,
email,
privilege='admin',
password=password,
is_staff=True,
is_admin=True
)
return new_user
class Employee(AbstractBaseUser):
PRIVILEGE_LEVEL = (
('Administrator', 'admin'),
('Staff', 'staff'),
('Member', 'member'),
)
# ID = models.IntegerField(verbose_name="ID", unique=True)
id = models.AutoField(primary_key=True)
name = models.CharField(verbose_name="Name", max_length=50, blank=True, unique=True)
email = models.EmailField(verbose_name="email", max_length=225, default='this#mail.com')
Department = models.CharField(max_length=50, choices=DEP_CHOICES, default='')
Role = models.CharField(max_length=50, choices=ROLE_CHOICES, default='')
# privilege = models.CharField(max_length=10, default='User')
privilege = models.CharField(max_length=120, choices=PRIVILEGE_LEVEL, default='member')
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
Also, 'id' is auto generated by django as the primary key field, so it doesnt have to be in the frontend form.
By default the django model form calls MyUserManager.create_user.
and based on the modifications i made above, it defaults to creating a user
without permissions. Unless is_admin and is_staff are implicitly set to True
To create a superuser from your current form, you can update MyUserManager.create_user like so,
def create_user(self, name, email, privilege='member', is_admin=False, is_staff=False, password=None):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
name=name,
email=self.normalize_email(email),
privilege=privilege,
)
user.set_password(password)
user.is_active = True
user.is_staff = is_staff
user.is_admin = is_admin
if privilege == 'admin':
user.is_superuser = True
user.save(using=self._db)
return user
But i would advise you update your CustomUserCreationForm instead as such,
class CustomUserCreationForm(UserCreationForm):
# ID = forms.CharField(max_length=50)
password = forms.CharField(widget=forms.PasswordInput)
class Meta(UserCreationForm):
model = Employee
fields = "__all__"
# ADD THIS
def clean(self, value):
print(self.data)
print(self.errors)
cleaned_data = self.cleaned_data
print(cleaned_data)
return cleaned_data
# ADD THIS
def save(self, *args, **kwargs):
data = self.cleaned_data
# email, password1 = v['email'], v['password1']
employee = None
if data['privilege'] == 'admin':
employee = Employee.objects.create_superuser(
name=data['name'],
email=data['email'],
password=data['password'],
)
else:
employee = Employee.objects.create_user(
name=data['name'],
email=data['email'],
password=data['password'],
)
# User is already saved after calling BaseUserManager function.
return employee
MyUserManager.create_superuser calls the MyUserManager.create_user and updates it based on parameter passed to it.
Let me know if you need further clarifications. Cheers.

DjangoRestFramework - How to update fields in model

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.

Categories