django form validation -validation error custom message not work - python

This is a Django rest project
I'm creating a user registration form .. I wrote a validation for username like below but my custom validation error is not showing and it shows a default message like below... how can I fix this?
My other question is: Whats the difference between def validate_username and def clean_username
Thank You
This is the default Django message:
"{
"username": [
"A user with that username already exists."
]
}
"
This is my view:
class UserRegisterApiView(CreateAPIView):
permission_classes = [AllowAny]
serializer_class = UserRegisterSerializer
queryset = User.objects.all()
This is my serilizer:
class UserRegisterSerializer(ModelSerializer):
#email2 = EmailField(label='confirm email')
email = EmailField(label='email', )
class Meta:
model = User
fields = [
'username',
'first_name',
'email',
'password',
]
extra_kwargs = {
"password": {
"write_only": True
}
}
# check if the user name is taken
def validate_username(self, value):
username = value
qs = User.objects.filter(username=username)
if qs.exists():
raise ValidationError("این نام کاربری آزاد نمیباشد")
return value

The uniquire message is come from models as:
username = models.CharField(
_('username'),
max_length=150,
unique=True,
help_text=_('Required. 150 characters or fewer. Letters, digits and #/./+/-/_ only.'),
validators=[username_validator],
error_messages={
'unique': _("A user with that username already exists."),
},
)
In your case,you need to rewrite your username's UniqueValidator in serializer.
class UserRegisterSerializer(ModelSerializer):
def __init__(self, *args, **kwargs):
super(UserRegisterSerializer, self).__init__(*args, **kwargs)
for validator in self.fields['username'].validators:
from rest_framework.validators import UniqueValidator
if type(validator) == UniqueValidator:
validator.message = 'این نام کاربری آزاد نمیباشد'

Related

Django Rest Framework - Post more info User from Foreign Key

I am new to Django Rest Framework and checked some tutorials. Now I am trying to create my own user profile with more fields like: company name, phone, ....I created OneToOneField (one-to-one relationship) table with more info for my extend user. Now i want to create new user with all fields in post method, but i got error. How can i fix this?
models.py
class MoreInfo(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
compName = models.CharField(max_length=100)
title = models.CharField(null=True,max_length=128)
birthday = models.DateField(null=True, blank=True)
phone = models.CharField(max_length=20,blank=True)
api/serializer.py
class MoreInforSerializer(serializers.ModelSerializer):
class Meta:
model = MoreInfo
fields = '__all__'
class CreateUserSerializer(serializers.ModelSerializer):
moreInfoUser = MoreInforSerializer()
class Meta:
model = User
fields = '__all__'
extra_kwargs = {'password':{'write_only':True}}
def create(self,validated_data):
user = User.objects.create(
email=validated_data['email'],
username = validated_data['username'],
password = make_password(validated_data['password'])
)
info_data = validated_data.pop('moreInfoUser')
moreInfo = MoreInfo.objects.create(
user = user,
compName = info_data['compName'],
title = info_data['title'],
birthday = info_data['birthday'],
phone = info_data['phone']
)
# user.save()
return user
views.py
class ListCreateUser(ListCreateAPIView):
serializer_class = CreateUserSerializer
def post(self, request, *args, **kwargs):
serializer = CreateUserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return JsonResponse({
'message': 'Create a new Info successful!'
}, status=status.HTTP_201_CREATED)
return JsonResponse({
'message': 'Create a new Info unsuccessful!'
}, status=status.HTTP_400_BAD_REQUEST)
urls.py
path('createUser',views.ListCreateUser.as_view()),
POST:
{
"username":"user5",
"password":"12345aA#",
"email":"user5#gmail.com",
"compName":"A",
"title":"test",
"birthday":"1997-05-04",
"phone":"01234567"
}
Table for create User
enter image description here
Errors:
Can't create new User
Bad Request: /createUser
"POST /createUser HTTP/1.1" 400 46
You have to upload moreInfoUser also because you set that in the serializer.
{
"username":"user5",
"password":"12345aA#",
"email":"user5#gmail.com",
"compName":"A",
"title":"test",
"birthday":"1997-05-04",
"phone":"01234567",
"moreInfoUser": {
"compName": "...",
"title": "...",
"birthday": "...",
"phone": "..."
}
}

user.save() not working properly when used in overriding serializer class's save() method

what i wanted was to send a post request with body containing email , username , password and password 2.
the serializer class has a save method which has been overriden so that it checks password1 is equal to password2 or not . if equal i wanted a user object to be created with email username and a password . and wanted it to be saved . im using User model of django.
error:
TypeError: Got a TypeError when calling User.objects.create(). This may be because you have a writable field on the serializer class tha
t is not a valid argument to User.objects.create(). You may need to make the field read-only, or override the RegistrationSerializer.create() method to handle this correctly.
Serializer Class:
class RegistrationSerializer(serializers.ModelSerializer):
password2 = serializers.CharField(style={'input_type': 'password'}, write_only=True)
class Meta:
model = User
fields = ['email', 'username', 'password','password2']
extra_kwargs = {'password': {'write_only': True}}
# override one of its method to check if passwords match
def save(self):
user = User()
#cant create user py passing into constructor
user.email=self.validated_data['email']
user.username=self.validated_data['username']
password=self.validated_data['password']
password2=self.validated_data['password2']
if password!=password2:
raise serializers.ValidationError({'password':'password must match'})
user.set_password(password)
user.save()
return user
the view called:
#api_view(['POST', ])
def registration_view(request):
serializer=RegistrationSerializer(data=request.data)
data={}
if serializer.is_valid():
user=serializer.save()
data['response']="successfully created"
data['email']=user.email
data['username']=user.username
else:
data=serializer.errors
return Response(data)
As save method is not good place for validation, You should use validate function when you want control some fields are correct.
class RegistrationSerializer(serializers.ModelSerializer):
password2 = serializers.CharField(style={'input_type': 'password'}, write_only=True)
class Meta:
model = User
fields = ['email', 'username', 'password','password2']
extra_kwargs = {'password': {'write_only': True}}
def validate(self, attrs):
if attrs.get('password') != attrs.get('password2'):
raise serializers.ValidationError({'password':'password must match'})
return attrs
def create(self, validated_data):
password2 = validated_data.pop('password2')
return super().create(validated_data)
If you want looks save function http://www.cdrf.co/3.9/rest_framework.serializers/ModelSerializer.html#save

Use email as authentication field and add email verification on django custom user model

I have this custom user model on my Django project. I want to make the email as authentication field instead of the username. Also, I want to perform an email verification.
models.py
class es_user(models.Model):
user = models.OneToOneField(User,related_name='es_user', on_delete=models.CASCADE),
is_activated = models.BooleanField(default=False)
def get_absolute_url(self):
return reverse('user_detail', kwargs={'id': self.pk })
view.py
def signup(request):
signup_form_instance = SignUpForm()
if request.method == "POST":
signup_form_instance = SignUpForm(request.POST)
if signup_form_instance.is_valid():
signup_form_instance2 = signup_form_instance.save(commit = False)
username = signup_form_instance2.username
password = signup_form_instance2.password
signup_form_instance2.password = make_password(signup_form_instance.cleaned_data['password'])
signup_form_instance2.save()
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request,user)
active_user = request.user
es_user_instance = es_user.objects.create(user= active_user)
# return index(request)
return redirect('index')
# return user_detail(request)#successful signup redirect or return
# return redirect('user_detail',id = [str(request.user.id) ])#kwargs={'id': request.user.id })
else:
print("SIGN UP FORM INVALID")
return render(request,'signup.html',{'signup_form':signup_form_instance})
forms.py
class SignUpForm(forms.ModelForm):
class Meta:
model = User
fields = ('username', 'email', 'password')
# for adding bootstrap classes & placeholders
widgets = {
'username': TextInput(attrs={
'class':'form-control',
'placeholder': 'Username *'}),
'email': EmailInput(attrs={
'class':'form-control',
'placeholder': 'Your Email *'}),
'password': PasswordInput(attrs={
'class':'form-control',
'placeholder': 'Your Password *'}),
}
help_texts = {
'username': None,
}
# to remove labels in form
labels = {
'username': (''),
'email':(''),
'password':(''),
}
My project is near completion so I cannot change my user model anymore or even change its name. So is there a way I can add email verification and using email instead of username for authentication without changing my user model.
I've seen a solution for a similar problem in this post . But I cannot use it since I use my custom user model es_user. is there a way in which I can edit it for my problem
To use Email as authentication, you have to use make new python file Backend.py and inside it write
class AuthenticationBackend(backends.ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
usermodel = get_user_model()
print(usermodel)
try:
user = usermodel.objects.get(Q(username__iexact=username) | Q(
email__iexact=username))
if user.check_password(password):
return user
except user.DoesNotExist:
pass
and add this AuthenticationBackend in settings.py as
AUTHENTICATION_BACKENDS = (
'users.backend.AuthenticationBackend',
'django.contrib.auth.backends.ModelBackend',
)
This will let you authenticate user with both username and password.
For second part of your question,Please follow:
Django Custom User Email Account Verification

Validate Sign Up User data in serializers - Django Rest Framework

I have an issue with Validate Sign Up User data in serializers - Django Rest Framework. Hope your guys help me!
My request:
I want to create sign up form with user enter Duplicate email, it'll raise serializer object which duplicate.
My serializers:
class UserDuplicateSerializer(ModelSerializer):
class Meta:
model = User
fields = [
'username',
'full_name',
'first_name',
'last_name',
]
class UserSignUpSerializer(ModelSerializer):
username = CharField(required=True, allow_blank=False)
class Meta:
model = User
fields = [
'username',
'email',
'password'
]
extra_kwargs = {"password": {"write_only": True}}
# Validate duplicate username
def validate_username(self, value):
data = self.get_initial()
username = data.get("username")
username_qs = User.objects.filter(username=username)
if username_qs.exists():
duplicate_obj = User.objects.get(username=username)
serializer = UserDuplicateSerializer(duplicate_obj)
raise ValidationError(format(serializer.data))
else:
pass
return value
def create(self, validated_data):
username = validated_data['username']
...
user_obj.save()
return validated_data
It renders:
{'username': u'duongnuhabang', 'first_name': u'D\u01b0\u01a1ng N\u1eef', 'profile_pic_url': OrderedDict([('id', 71), ('image', '/media/users/2/13_71.jpg'), ('config_translateY', 0)]), 'last_name': u'H\u1ea1 B\u0103ng', 'full_name': u'D\u01b0\u01a1ng N\u1eef H\u1ea1 B\u0103ng'}
But I want to JSON Type:
{'username': 'duongnuhabang', 'first_name': 'Feed Git', ...}
raise ValidationError("This username has been registered!" +str( serializer.data))
use this in your validation error

Django: How to login user directly after registration using generic CreateView

With django generic CreateView I can create a new user account, but how can I login this user automatically after registration using this technique?
urls.py
...
url( r'^signup/$', SignUpView.as_view(), name = 'user_signup' ),
...
views.py
class SignUpView ( CreateView ) :
form_class = AccountCreationForm
template_name = 'accounts/signup.html'
success_url = reverse_lazy( 'home' )
forms.py
class AccountCreationForm ( forms.ModelForm ) :
def __init__( self, *args, **kwargs ) :
super( AccountCreationForm, self ).__init__( *args, **kwargs )
for field in self.fields :
self.fields[field].widget.attrs['class'] = 'form-control'
password1 = forms.CharField( label = 'Password', widget = forms.PasswordInput )
password2 = forms.CharField( label = 'Password confirmation', widget = forms.PasswordInput )
class Meta :
model = User
fields = ( 'email', 'first_name', )
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 password
def save( self, commit = True ) :
# Save the provided password in hashed format
user = super( AccountCreationForm, self ).save( commit = False )
user.set_password( self.cleaned_data[ "password1" ] )
if commit:
user.save()
return user
it's maybe late but that was exactly my question, and after some hours of struggling finally find out.
Maybe you found but if other people are looking for a solution, here is mine.
You just have to override form_valid() in your class Inheriting CreateView. Here is the example with my own class :
class CreateArtistView(CreateView):
template_name = 'register.html'
form_class = CreateArtistForm
success_url = '/'
def form_valid(self, form):
valid = super(CreateArtistView, self).form_valid(form)
username, password = form.cleaned_data.get('username'), form.cleaned_data.get('password1')
new_user = authenticate(username=username, password=password)
login(self.request, new_user)
return valid
I first catch the value of my parent class method form_valid() in valid, because when you call it, it calls the form.save(), which register your user in database and populate your self.object with the user created.
After that I had a long problem with my authenticate, returning None. It's because I was calling authenticate() with the django hashed password, and authenticate hash it again.
Explaining this for you to understand why I use form.cleaned_data.get('username') and not self.object.username.
I hope it helps you or other, since I didn't find a clear answer on the net.
In Django 2.2 I didn't managed to have it working as Bestasttung posted. But I managed with a small change in the form_valid method.
class CreateAccountView(CreateView):
template_name = 'auth/create_account.html'
form_class = SignInForm
success_url = '/'
def form_valid(self, form):
valid = super().form_valid(form)
# Login the user
login(self.request, self.object)
return valid

Categories