I want to erase username, password2 field from rest auth and add nickname and profile image. So we made the code as follows, but Nickname and profile image were added normally, but username and password2 were not erased. How can I erase them? Here is my code.
models.py
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, PermissionsMixin
from django.utils.translation import ugettext_lazy as _
class UserManager(BaseUserManager):
use_in_migrations = True
def create_user(self, email, profile, nickname, password):
user = self.model(
email=self.normalize_email(email),
nickname=nickname,
profile=profile,
)
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.staff = True
user.admin = True
user.save(using=self._db)
return user
class User(AbstractBaseUser, PermissionsMixin):
username = None
email = models.EmailField(_('email address'), unique=True)
nickname = models.CharField(max_length=10)
profile = models.ImageField(default='default_image.jpeg')
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
serializers.py
from rest_framework_simplejwt.serializers import TokenObtainSerializer
from .models import User
from rest_framework import serializers
from rest_auth.registration.serializers import RegisterSerializer
from allauth.account import app_settings as allauth_settings
from allauth.utils import email_address_exists
from allauth.account.adapter import get_adapter
from allauth.account.utils import setup_user_email
from django.utils.translation import ugettext_lazy as _
class CustomRegisterSerializer(RegisterSerializer):
nickname = serializers.CharField(required=True)
profile = serializers.ImageField(use_url=True)
def validate_email(self, email):
email = get_adapter().clean_email(email)
if allauth_settings.UNIQUE_EMAIL:
if email and email_address_exists(email):
raise serializers.ValidationError(
_("A user is already registered with this e-mail address."))
return email
def validate_password1(self, password):
return get_adapter().clean_password(password)
def get_cleaned_data(self):
return {
'email': self.validated_data.get('email', ''),
'password': self.validated_data.get('password', ''),
'nickname': self.validated_data.get('nickname', ''),
'profile': self.validated_data.get('profile', ''),
}
def save(self, request):
adapter = get_adapter()
user = adapter.new_user(request)
self.cleaned_data = self.get_cleaned_data()
adapter.save_user(request, user, self)
setup_user_email(request, user, [])
user.save()
return user
class userSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('email','password', 'nickname','profile')
views.py
class customSignUpView (RegisterView) :
serializer_class = CustomRegisterSerializer
thank in advance
Add this to your settings.py file, your custom serializer route and it will work fine
REST_AUTH_REGISTER_SERIALIZERS = {
'REGISTER_SERIALIZER': 'your_app_name.serializers.CustomRegisterSerializer'
}
Related
I am able to create a New User using the "register" endpoint. I can the user being created on the admin page as well. When I try to get an access token for the newly created user I get the error "detail": "No active account found with the given credentials". I am correctly passing the valid credentials so I don't know what the problem might be. Here I have demonstrated the same.
Here goes the code:
serializers.py
from rest_framework import serializers
from .models import CustomUser
from django.contrib.auth.hashers import make_password
class RegisterUserSerializers(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ('email', 'password')
extra_kwargs = {"password": {"write_only": True}}
def create(self, validated_data):
password = validated_data.pop('password', None)
instance = self.Meta.model(**validated_data)
if password is not None:
instance.set_password(password)
instance.save()
return instance
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)
views.py
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.permissions import AllowAny
from .serializers import RegisterUserSerializers
from rest_framework_simplejwt.tokens import RefreshToken
class CustomUserCreate(APIView):
permission_classes = [AllowAny]
def post(self, request):
reg_serial = RegisterUserSerializers(data=request.data)
if reg_serial.is_valid():
newUser = reg_serial.save()
if newUser:
context = {
"message": f"User created {newUser}"
}
return Response(context, status=status.HTTP_201_CREATED)
return Response(reg_serial.errors, status=status.HTTP_400_BAD_REQUEST)
class BlacklistTokenView(APIView):
permission_classes = [AllowAny]
def post(self, request):
try:
refresh_token = request.data["refresh_token"]
token = RefreshToken(refresh_token)
token.blacklist()
except Exception as e:
return Response(status=status.HTTP_400_BAD_REQUEST)
models.py
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
class CustomUserManager(BaseUserManager):
def create_superuser(self, email, password, **other_fields):
other_fields.setdefault('is_staff', True)
other_fields.setdefault('is_superuser', True)
other_fields.setdefault('is_active', True)
if other_fields.get('is_staff') is not True:
raise ValueError(
'Superuser must be assigned to is_staff=True.')
if other_fields.get('is_superuser') is not True:
raise ValueError(
'Superuser must be assigned to is_superuser=True.')
return self.create_user(email, password, **other_fields)
def create_user(self, email, password, **other_fields):
if not email:
raise ValueError(_('You must provide an email address'))
email = self.normalize_email(email)
user = self.model(email=email, **other_fields)
user.set_password(password)
user.save()
return user
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
objects = CustomUserManager()
USERNAME_FIELD = 'email'
# REQUIRED_FIELDS = ['user_name', 'first_name']
def __str__(self):
return self.email
In your CustomUser model you are the is_active field is defined with default=False, you can change it to default=True or set the user to active during the registration process.
I'm trying to solve some of the things that don't fit me in the current django rest auth.
First of all, I would like to make it possible to sign up as a member only once I enter the password without using password2 in the rest auth.
And when I sign up as a member, the following error occurs when I insert the duplicate email.
UNIQUE constraint failed: api_user.email
How can I solve these problems? Here is my code.
models.py
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, PermissionsMixin
from django.utils.translation import ugettext_lazy as _
class UserManager(BaseUserManager):
use_in_migrations = True
def create_user(self, email, profile, userName, password):
user = self.model(
email=self.normalize_email(email),
userName=userName,
profile=profile,
)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, userName, profile):
user = self.create_user(
email=self.normalize_email(email),
password=password,
userName=userName,
profile=profile,
)
user.is_staff = True
user.is_superuser = True
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
username = None
email = models.EmailField(_('email address'), unique=True)
userName = models.CharField(max_length=10)
profile = models.ImageField(default='default_image.jpeg')
is_staff = models.BooleanField(_('staff status'), default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['userName', 'profile']
serializers.py
from .models import User
from rest_framework import serializers
from rest_auth.registration.serializers import RegisterSerializer
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer, TokenRefreshSerializer
from rest_framework_simplejwt.tokens import RefreshToken
from allauth.account import app_settings as allauth_settings
from allauth.utils import email_address_exists
from allauth.account.adapter import get_adapter
from allauth.account.utils import setup_user_email
from django.utils.translation import ugettext_lazy as _
from datetime import datetime, timedelta
class customRegisterSerializer(RegisterSerializer):
username = None
userName = serializers.CharField(required=True)
profile = serializers.ImageField(use_url=True)
def validate_email(self, email):
email = get_adapter().clean_email(email)
if allauth_settings.UNIQUE_EMAIL:
if email and email_address_exists(email):
raise serializers.ValidationError(
_("A user is already registered with this e-mail address."))
return email
def validate_password(self, password):
return get_adapter().clean_password(password)
def get_cleaned_data(self):
return {
'email': self.validated_data.get('email', ''),
'password': self.validated_data.get('password', ''),
'userName': self.validated_data.get('userName', ''),
'profile': self.validated_data.get('profile', ''),
}
def save(self, request, **kwargs) :
adapter = get_adapter()
user = adapter.new_user(request)
user.save()
return user
class customTokenObtainPairSerializer(TokenObtainPairSerializer):
def validate(self, attrs):
data = super().validate(attrs)
refresh = self.get_token(self.user)
del(data['refresh'])
del(data['access'])
data['token_type'] = 'bearer'
data['access_token'] = str(refresh.access_token)
data['expires_at'] = str(datetime.now() + timedelta(hours=6))
data['refresh_token'] = str(refresh)
data['refresh_token_expires_at'] = str(datetime.now() + timedelta(days=30))
return data
class customTokenRefreshSerializer (TokenRefreshSerializer) :
def validate(self, attrs):
data = super().validate(attrs)
refresh = RefreshToken(attrs['refresh'])
del(data['refresh'])
data['token_type'] = 'bearer'
data['access_token'] = str(refresh.access_token)
data['expires_at'] = str(datetime.now() + timedelta(hours=6))
data['refresh_token'] = str(refresh)
data['refresh_token_expires_at'] = str(datetime.now() + timedelta(days=30))
return data
thanks in advance
I created Django custom user model and added restframework to it. Custom User fields are fname, lname, email,username,password,phone ,gender,acctype.
when I register user through the Django restframework, it only takes username,email and password and other field are become empty. what is the problem
my models.py file
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager,User
# Create your models here.
GENDER_CHOICES = (
('M', 'Male'),
('F', 'Female')
)
class AccountManager(BaseUserManager):
def create_user(self, email, username, phone, gender, password=None, **extrafields):
if not email:
raise ValueError("email is needed")
if not username:
raise ValueError("username is needed")
if not phone:
raise ValueError("Phone is needed")
if not gender:
raise ValueError("gender is needed")
user= self.model(
email=self.normalize_email(email),
username=username,
phone=phone,
gender=gender,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self,email,username,phone,gender,password,**extrafields):
user=self.create_user(
email=self.normalize_email(email),
password=password,
username=username,
phone=phone,
gender=gender,
)
user.is_admin=True
user.is_staff=True
user.is_superuser=True
user.save(using=self._db)
return user
class Account(AbstractBaseUser):
ACCTYPE = (
('Student', 'Student'),
('Staff', 'Staff')
)
fname=models.CharField(verbose_name='fname', max_length=30)
lname=models.CharField(verbose_name='lname', max_length=30)
email = models.EmailField(verbose_name='E-mail', max_length=30, unique=True)
username = models.CharField(verbose_name='Username', max_length=30, unique=True)
last_login = models.DateTimeField(verbose_name='Last Login', auto_now=True)
phone = models.CharField(verbose_name='Phone', max_length=10)
gender = models.CharField(choices=GENDER_CHOICES, max_length=128)
acctype = models.CharField(max_length=16, choices=ACCTYPE)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_verified = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS=['email', 'phone', 'gender']
objects=AccountManager()
def __str__(self):
return self.username
def has_perm(self,perm,obj=None):
return self.is_admin
def has_module_perms(self, app_lebel):
return True
serializer.py
from rest_framework import serializers
from rest_auth.registration.serializers import RegisterSerializer
from accounts.models import Account
from rest_auth.registration.serializers import RegisterSerializer
class CustomRegisterSerializer(RegisterSerializer):
fname = serializers.CharField(required=True)
lname = serializers.CharField(required=True)
username=serializers.CharField(required=True)
email = serializers.EmailField(required=True)
password1 = serializers.CharField(write_only=True)
phone=serializers.CharField(required=True)
gender=serializers.CharField(required=True)
acctype=serializers.CharField(required=True)
def get_cleaned_data(self):
super(CustomRegisterSerializer, self).get_cleaned_data()
return {
'password1': self.validated_data.get('password1', ''),
'email': self.validated_data.get('email', ''),
'username': self.validated_data.get('username', ''),
'fname': self.validated_data.get('fname', ''),
'lname': self.validated_data.get('lname', ''),
'phone': self.validated_data.get('phone', ''),
'acctype': self.validated_data.get('acctype', ''),
'gender': self.validated_data.get('gender', ''),
}
class CustomUserDetailsSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ('pk','email','fname','lname','username','phone','gender','acctype')
read_only_fields = ('email','acctype','fname','lname')
views.py
from django.shortcuts import render
from rest_framework import generics
from rest_auth.registration.views import RegisterView
from .models import Account
# Create your views here.
class CustomRegisterView(RegisterView):
queryset = Account.objects.all()
Django-allauth doesn't allow saving custom fields by default
To solve this problem I refined a save function inside CustomRegisterSerializer and simply assign the custom field values. Then saved it using user.save()
def save(self, request):
adapter = get_adapter()
user = adapter.new_user(request)
self.cleaned_data = self.get_cleaned_data()
adapter.save_user(request, user, self)
setup_user_email(request, user, [])
user.fname=self.cleaned_data.get('fname')
user.lname=self.cleaned_data.get('lname')
user.phone=self.cleaned_data.get('phone')
user.acctype=self.cleaned_data.get('acctype')
user.gender=self.cleaned_data.get('gender')
user.save()
return user
serializer.py
from rest_framework import serializers
from accounts.models import Account
class CustomRegisterSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = '__all__'
views.py
from rest_framework import viewsets
from .models import Account
from .serializer import CustomRegisterSerializer # import serializer as your path defined
class CustomRegisterView(viewsets.ModelViewSet):
serializer_class = CustomRegisterSerializer
queryset = Account.objects.all()
the code below is a simple register for an account now when I submit this form it redirects me to the home page and this means that my form is valid and works but when I check my Admin page I see that account is not registered and I get no error. therefor I can understand here that my code is already working but it hasn't been saved.
so, how can I save member through FormView?
thanks in advance
views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.views.generic import TemplateView, View
from django.views.generic.edit import FormView, CreateView
from .forms import UserForm
from .models import User
from django.urls import reverse_lazy
class IndexView(TemplateView):
template_name = "accounts/index.html"
class ProfileView(CreateView):
template_name = 'accounts/register.html'
success_url = reverse_lazy('accounts:index')
form_class = UserForm
forms.py
from django import forms
from .models import User
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(label="Confirm Password", widget=forms.PasswordInput)
class Meta:
model = User
fields = '__all__'
exclude = ('staff', 'active', 'admin', 'last_login')
def clean_password2(self):
password = self.cleaned_data['password']
password2 = self.cleaned_data['password2']
if password and password2 and password != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def clean_email(self):
email = self.cleaned_data['email']
qs = User.objects.filter(email=email)
if qs.exists():
raise forms.ValidationError("email is taken")
return email
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data['password'])
if commit:
user.save()
return user
models.py
from django.db import models
from django.contrib.auth.models import (AbstractBaseUser, BaseUserManager)
from django.db.models.signals import post_save
from django.dispatch import receiver
class UserManager(BaseUserManager):
def create_user(self, email, password, username, is_staff=True, is_admin=True, is_active=True):
if not email:
raise ValueError("This email is invalid")
if not password:
raise ValueError("This Password is invalid")
if not username:
raise ValueError("This Username is invalid")
user = self.model(
email=self.normalize_email(email)
)
user.staff = is_staff
user.admin = is_admin
user.active = is_active
user.set_password(password)
user.username = username
user.save(using=self._db)
return user
def create_staffuser(self, email, password, username):
user = self.create_user(
email,
password=password,
username=username,
is_staff=True,
)
return user
def create_superuser(self, email, password, username):
user = self.create_user(
email=email,
password=password,
username=username,
is_staff=True,
is_admin=True,
)
return user
class User(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True, verbose_name="Email")
first_name = models.CharField(max_length=255, verbose_name="First Name")
last_name = models.CharField(max_length=255, verbose_name="Last Name")
username = models.CharField(max_length=50, unique=True, verbose_name="Username")
active = models.BooleanField(default=True, verbose_name="Active")
staff = models.BooleanField(default=False, verbose_name="Staff")
admin = models.BooleanField(default=False, verbose_name="Admin")
timestamp = models.DateTimeField(auto_now_add=True, verbose_name="Time Stamp")
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username"]
objects = UserManager()
def __str__(self):
return self.username
def get_short_name(self):
return self.username
def get_full_name(self):
return self.username
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.staff
#property
def is_admin(self):
return self.admin
#property
def is_active(self):
return self.active
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
article = models.TextField(blank=True, max_length=500, verbose_name="Article")
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = User.objects.create(user=kwargs['instance'])
post_save.connect(receiver=create_profile, sender=User)
Because a FormView doesn't save() the form. It's meant to be used with any form, not just ModelForms. Not every Form has a save() method.
The only thing the FormView does in form_valid() is redirect to the success url. You have to tell it yourself what you it to do after the form was verified to be valid:
def form_valid(self, form):
form.save()
return super().form_valid(form)
You can see the inner workings of FormView here.
You could use a CreateView instead of a FormView. That would do the saving for you.
I am new to Django, trying to create a custom user for my project. When I am running the server, it raises No module named 'django.contrib.customuser' and sometimes, Manager isn't available; auth.User has been swapped for Mysite.CustomUser. Even i changed my settings: django.contrib.auth to django.contrib.custommuser. Please someone help me solving this. Here's my code
models.py:
from datetime import datetime
from django.db import models
from django.contrib.auth.models import User, BaseUserManager, AbstractUser, AbstractBaseUser
from django.utils.translation import ugettext_lazy as _
class CustomUserManager(BaseUserManager):
def _create_user(self, username, email, u, password, is_staff, is_active, **extra_fields):
now = datetime.now()
if not email:
raise ValueError('Users must have an email address')
email = self.normalize_email(email)
user = self.model(username=username, email=email, u=u, password=password,
is_staff=is_staff, is_active=False, last_login=now, date_joined=now, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, username, email, u, password = None, **extra_fields):
return self._create_user(username, email, u, False, False, **extra_fields)
def create_superuser(self, username, email, u, password = None):
user = self._create_user(username, email, u, password, True, True)
user.set_password(password)
user.is_active=True
user.is_admin = True
user.is_superuser = True
user.save(using=self._db)
return user
class CustomUser(AbstractBaseUser):
username = models.CharField(max_length=30)
email = models.EmailField(max_length=30, unique=True, db_index=True)
password1 = models.CharField(max_length=30)
password2 = models.CharField(max_length=30)
CHOICES= (('LinkedinUser', 'LinkedinUser'),('FacebookUser', 'FacebookUser'),)
u = models.CharField(choices=CHOICES, max_length=20, default=0)
date_joined = models.DateTimeField(_('date joined'), default=datetime.now)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
REQUIRED_FIELDS = ('username', 'u')
USERNAME_FIELD = 'email'
objects = CustomUserManager()
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def get_full_name(self):
# The user is identified by their email address
return self.email
def get_short_name(self):
# The user is identified by their email address
return self.email
def __str__(self): # __unicode__ on Python 2
return self.email
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
#property
def is_staff(self):
return self.is_admin
forms.py
from django import forms
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from .models import CustomUser#, LinkedInUser, FacebookUser
import re
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import get_user_model
class CustomUserForm(forms.ModelForm):
username = forms.RegexField(regex=r'^\w+$', widget=forms.TextInput(attrs=dict(required=True, max_length=30)), label=_("username"), error_messages={ 'invalid': _("This value must contain only letters, numbers and underscores.") })
email = forms.EmailField(widget=forms.TextInput(attrs=dict(required=True, max_length=30)), label=_("Email address"))
password1 = forms.CharField(widget=forms.PasswordInput(attrs=dict(required=True, max_length=30, render_value=False)), label=_("Password"))
password2 = forms.CharField(widget=forms.PasswordInput(attrs=dict(required=True, max_length=30, render_value=False)), label=_("Password (again)"))
CHOICES= (('LinkedinUser', 'LinkedinUser'),('FacebookUser', 'FacebookUser'),)
u = forms.ChoiceField(choices=CHOICES, label='ID', widget=forms.RadioSelect())
class Meta :
model = CustomUser
fields = [ 'username', 'email', 'password1', 'password2', 'u' ]
User = get_user_model()
def clean_name(self):
try:
user = User.objects.get(username__iexact=self.cleaned_data['username'])
except User.DoesNotExist:
return self.cleaned_data['username']
raise forms.ValidationError(_("The username already exists. Please try another one."))
def clean(self):
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError(_("The two password fields did not match."))
return self.cleaned_data
class CustomUserCreationForm(UserCreationForm):
"""
A form that creates a user, with no privileges, from the given email and
password.
"""
def __init__(self, *args, **kargs):
super(CustomUserCreationForm, self).__init__(*args, **kargs)
del self.fields['username']
class Meta:
model = CustomUser
fields = ("email",)
admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import get_user_model
from .models import CustomUser
from .forms import CustomUserCreationForm
class CustomUserAdmin(admin.ModelAdmin):
form = CustomUserCreationForm
admin.site.register(CustomUser, CustomUserAdmin)
backends.py:
from models import CustomUser
class CustomUserAuth(object):
def authenticate(self, username=None, password=None):
try:
user = CustomUser.objects.get(email=username)
if user.check_password(password):
return user
except CustomUser.DoesNotExist:
return None
def get_user(self, user_id):
try:
user = CustomUser.objects.get(pk=user_id)
if user.is_active:
return user
return None
except CustomUser.DoesNotExist:
return None
Remove django.contrib.customuser and django.contrib.auth from your INSTALLED_APPS. There is no customuser application under django.contrib package, and auth can be omitted (to avoid potential name colission).
Furthermore, I suggest you re-read the Django docs on auth customization. Most of the changes are optional, and your code should be simplified by re-using the base classes, unless your methods vary of course.
The docs also mentions that for swapping User models, you are required to update settings to AUTH_USER_MODEL = 'customuser.CustomUser'.