I have a RegisterForm that inherits from ModelForm with RegisterView that inherits from FormView. If every field data is valid, the user gets successfully created and is redirected to login page. But if there is a validation error, it shows the field error below that field and the form gets refreshed and all the fields data is lost. How to avoid form refreshing so that user need not to fill the details again and again.
forms.py
class RegisterForm(forms.ModelForm, PasswordValidatorMixin):
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField( label='Confirm password', widget=forms.PasswordInput)
class Meta:
model = UserModel
fields = (
'first_name',
'last_name',
'username',
'password1',
'password2',
'current_email',
)
def __init__(self, social_email=None, social_fname=None, social_lname=None,
social_uname=None,*args, **kwargs):
super(RegisterForm, self).__init__(*args, **kwargs)
self.current_email = None
self.social_email = social_email
self.social_fname = social_fname
self.social_lname = social_lname
self.social_uname = social_uname
def clean(self, *args, **kwargs):
username = self.cleaned_data.get('username')
self.current_email = self.cleaned_data.get('current_email')
if self.social_email:
self.current_email = self.social_email
if not username:
raise forms.ValidationError({"username":"Username can't be empty"})
if not self.current_email:
raise forms.ValidationError({"current_email":"Email can't be empty"})
qs = UserModel.objects.filter(username=username)
qs_email = UserModel.objects.filter(current_email=self.current_email)
if qs.exists():
raise forms.ValidationError({"username":"Username is already taken"})
if qs_email.exists():
raise forms.ValidationError({"current_email":"Email has already been registered"})
return self.cleaned_data
def save(self, commit=True):
user = super().save(commit=False)
current_email = self.cleaned_data.get('current_email')
password = self.cleaned_data.get('password1')
user.set_password(password)
if self.social_email:
user.is_active = True
user.save()
return user
views.py
class RegisterView(ContextMixin, FormView):
form_class = RegisterForm
template_name = 'accounts/register.html'
title = 'Register'
#method_decorator(sensitive_post_parameters('password'))
#method_decorator(csrf_protect)
#method_decorator(never_cache)
def dispatch(self, *args, **kwargs):
self.kwargs['social_email'] = SOCIAL_USER_EMAIL
self.kwargs['social_fname'] = SOCIAL_USER_FNAME
self.kwargs['social_lname'] = SOCIAL_USER_LNAME
if SOCIAL_USER_EMAIL:
self.kwargs['social_uname'] = SOCIAL_USER_EMAIL.split('#',1)[0]
return super(RegisterView, self).dispatch(*args, **kwargs)
# Passes view kwargs to html
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if SOCIAL_USER_EMAIL:
context['social_email'] = self.kwargs['social_email']
context['social_fname'] = self.kwargs['social_fname']
context['social_lname'] = self.kwargs['social_lname']
context['social_uname'] = self.kwargs['social_uname']
# context['social_image'] = SOCIAL_USER_IMAGE
return context
# Passes view kwargs to form
def get_form_kwargs(self):
kwargs = super(RegisterView, self).get_form_kwargs()
kwargs.update(self.kwargs)
return kwargs
def form_valid(self, form):
form.save()
if not self.kwargs['social_email']:
return render(self.request, 'accounts/success.html', {
'title':"You've registered successfully",
'body':"You've successfully registered at antef! Please verify the link sent at " +
form.current_email
})
return render(self.request, 'accounts/success.html', {
'title':"You've registered successfully",
'body':"You've successfully registered with your " + self.kwargs['social_email'] + " account."})
First, you don't need validation error for empty inputs, just add required = True in your forms.py or in your model.
Second you are not returning anything after validation error, which making your form empty after refresh.
You can also check email and username separately, for better use,
def clean_email(self):
email = self.cleaned_data.get('email')
if your_condition:
raise forms.ValidationError()
return email
def clean_username(self):
username = self.cleaned_data.get('username')
if your_condition
raise forms.ValidationError
return username
Related
I'm now making user profile update API using drf with RetreiveUpadteAPIView
there is one question that i can't figure out what the solution is.
This is what i want. I wanna update password and update other user data once for all.
changing password is worked as well as i supposed but other user datas (nick_name', 'wannabe', 'profile_img') are not save on DB through this logic below.
When i do self.object.set_password(), self.object.save() first and then do perform_update after. then user datas are well updated on DB. but password is saved without hashed even if i do set_password which is make the password hashed.
How can i fix it..
your best regard
Here is my code below.
#views.py
#permission_classes([IsAuthenticated])
class UpdatePartialUserView(RetrieveUpdateAPIView):
queryset = User.objects.all()
serializer_class = UserProfileSerializer
def get_object(self):
queryset = self.filter_queryset(self.get_queryset())
obj = queryset.get(pk=self.request.user.id)
self.check_object_permissions(self.request, obj)
return obj
def retrieve(self, request, *args, **kwargs):
serializer = UserSerializer(request.user)
return Response(status=status.HTTP_200_OK, data = serializer.data)
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
self.object = self.get_object()
serializer = self.get_serializer(request.user, data = request.data, partial=partial)
# serializer = self.get_serializer(self.object, data = request.data, partial=partial)
if not serializer.is_valid(raise_exception=True):
return Response(status=status.HTTP_409_CONFLICT, data = {'message':serializer.errors})
self.perform_update(serializer=serializer)
#make password hashed
self.object.set_password(request.data['password'])
self.object.save()
return Response(status=status.HTTP_202_ACCEPTED, data={"message": "success!"})
#serializers.py
class UserProfileSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=True)
password2 = serializers.CharField(write_only=True, required=True)
old_password = serializers.CharField(write_only=True, required=True)
profile_img = serializers.ImageField(use_url=True, required = False)
def validate(self, attrs):
if attrs.get('password') != attrs.get('password2'):
raise serializers.ValidationError({
"password" : "passwords are not paired."})
return attrs
def validate_old_password(self, value):
#check user
request = self.context.get('request')
if request and hasattr(request, "user"):
user = request.user
if not user.check_password(value):
raise serializers.ValidationError({
"old_password" : "Old password is not correct."
})
return value
class Meta:
model = User
fields = ['nick_name', 'wannabe', 'old_password', 'password', 'password2', 'profile_img']
I think something like that should work.
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
self.object = self.get_object()
serializer = self.get_serializer(request.user, data = request.data, partial=partial)
if not serializer.is_valid(raise_exception=True):
return Response(status=status.HTTP_409_CONFLICT, data = {'message':serializer.errors})
self.object.set_password(new_password)
self.object.update(
nick_name=serializer.data["nickname"],
wannabe=serializer.data["wannabe"],
profile_img=serializer.data["profile_img"],
)
self.object.save()
return Response(status=status.HTTP_202_ACCEPTED, data={"message": "success!"})
I have a register user form which is doing all the validation as expected. However, it is not saving. I am not able to figure out the reason. How do I debug it ? Any help ? I am a newbie to forms and formviews any good document with example would really help me.
class RegisterForm(forms.ModelForm):
phone_number = forms.IntegerField(required=True)
password1 = forms.CharField(widget=forms.PasswordInput())
password2 = forms.CharField(widget=forms.PasswordInput())
country_code = forms.IntegerField()
#schools = school.objects.all()
#school_name = forms.ModelChoiceField(queryset=school.objects.distinct())
MIN_LENGTH = 4
class Meta:
model = User
fields = ['username','country_code','phone_number', 'password1', 'password2',
'full_name' ]
def clean_phone_number(self):
phone_number = self.data.get('phone_number')
print(phone_number)
if User.objects.filter(phone_number=phone_number).exists():
raise forms.ValidationError(
_("Another user with this phone number already exists"))
if len(phone_number) == 10 and phone_number.isdigit():
pass
else:
raise forms.ValidationError(
_("Invalid Phone Number"))
return phone_number
def save(self, *args, **kwargs):
print("saving")
user = super(RegisterForm, self).save(*args, **kwargs)
user.set_password(self.cleaned_data['password1'])
print('Saving user with country_code', user.country_code)
user.save()
return user
Views.py
class RegisterView(SuccessMessageMixin, FormView):
template_name = 'register-2.html'
form_class = RegisterForm
success_message = "One-Time password sent to your registered mobile number.\
The verification code is valid for 10 minutes."
def form_valid(self, form):
full_name=self.request.POST["full_name"]
user = form.save()
print(user.id)
username = self.request.POST['username']
password = self.request.POST['password1']
user = authenticate(username=username, password=password)
kwargs = {'user': user}
self.request.method = 'POST'
print("User created")
The print in clean_phone_number works however, save does not work
I had issue in the my form. One of the field was disabled and the value was not captured because of that.
However to identify that I used
def form_invalid(self,form):
# Add action to invalid form phase
messages.error(self.request, form.errors)
return self.render_to_response(self.get_context_data(form=form))
I have a registration page that allows a user to sign up. After doing so, I want to call an API and then, save the data to my model (not saving it to a form though). I tried doing this:
models.py:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE, primary_key=True, related_name = 'profile')
address = models.TextField()
birthday = models.DateField()
def __str__(self):
return str(self.user)
views.py:
def signup(request):
if request.method == 'POST':
user_form = UserForm(request.POST)
register_form = RegisterForm(request.POST)
if user_form.is_valid() and register_form.is_valid():
username = user_form.cleaned_data.get('username'),
first_name = user_form.cleaned_data.get('first_name'),
last_name=user_form.cleaned_data.get('last_name'),
email=user_form.cleaned_data.get('email'),
password=user_form.cleaned_data.get('password2'),
birthday = register_form.cleaned_data.get('dob'),
address=register_form.cleaned_data.get('address'),
payload = {'username': username,'first_name': first_name,'last_name': last_name,'email':email,'password':password,'register' : {'birthday': birthday,'address': address}}
response = requests.post('http://127.0.0.1:8000/my_api/',json=payload)
return redirect("home") #re-direct if login is successful
else:
user_form = UserForm()
register_form = RegisterForm()
return render(request, 'users/register.html', {'user_form': user_form, 'register_form': register_form})
class RegisterAPI(APIView):
permission_classes = [AllowAny]
def post(self, request, format=None):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
content = {'status': 'You are registered'}
return Response(content, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializers.py:
from users.models import Profile
from django.contrib.auth.models import User
class ProfileSerializer(serializers.ModelSerializer):
birthday = serializers.DateField(format="%Y-%m-%d")
class Meta:
model = Profile
fields = ('birthday','address')
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = User
fields = ('username','first_name','last_name','email', 'password', 'profile')
def create(self, request, validated_data, *args, **kwargs):
register_data = validated_data.pop('profile')
password = validated_data.pop('password', None)
user = User.objects.create(**validated_data)
if password is not None:
user.set_password(password)
user.save()
Profile.objects.create(user = user, **register_data)
return validated_data
However, I am getting this error:
Object of type data is not JSON serializable error in Django
It seems that it's got to do with the birthday. On my template, a user can display the date of birth as 'YYYY-MM-DD'. How can I fix this error?
The create method in your UserSerializer should return a User instance instead of validated_data.
def create(self, request, validated_data, *args, **kwargs):
register_data = validated_data.pop('profile')
password = validated_data.pop('password', None)
user = User.objects.create(**validated_data)
if password is not None:
user.set_password(password)
user.save()
Profile.objects.create(user = user, **register_data)
return user
I use a custom form inherited from django's UserCreationForm to add user. How ever i have to set different initial value for username field.It works perfectly but after hitting save button the user get saved with a different username than the initial value shown in the form.You can find the code below
from django.contrib.auth.forms import UserCreationForm
class AdminUserCreationForm(UserCreationForm):
"""
AdminForm for creating an instance of custom USER_MODEL.
"""
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ("username", "email")
field_classes = {'username': UsernameField}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.initial['username'] = random_username_generator()
self.fields['username'].disabled = True
self.fields['password1'].required = False
self.fields['password2'].required = False
def clean_username(self):
username = self.cleaned_data['username'].lower()
try:
User.objects.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError('A user with username {} already exists'.format(username))
def clean_email(self):
email = self.cleaned_data['email'].lower()
try:
User.objects.get(email=email)
except User.DoesNotExist:
return email
raise forms.ValidationError('A user with email {} already exists'.format(email))
def save(self, commit=True):
import ipdb; ipdb.set_trace();
user = super(AdminUserCreationForm, self).save(commit=False)
# user = self.instance
qb = QuickBlox()
qb_password = reset_password_generator()
user.qb_password = qb_password + 'vx'
user.save()
attempt = LoginAttempts()
attempt.user = user
attempt.save()
send_invite_mail(user)
return user
Very, very new to Django. I'm attempting to create a user registration process with custom form inputs. However, I have a few issues with the general persisting of new users to the database. This is what I have defined in my forms.py:
class UserRegistrationForm(UserCreationForm):
required_css_class = 'required'
email = forms.EmailField()
first_name = forms.CharField()
last_name = forms.CharField()
class Meta:
model = User
fields = ('username', 'email', 'first_name', 'last_name')
def __init__(self, *args, **kwargs):
super(UserRegistrationForm, self).__init__(*args, **kwargs)
self.fields['username'].widget = TextInput(attrs={'placeholder': 'Username'})
self.fields['username'].required = True
self.fields['username'].error_messages = {'required': 'Please enter your username'}
self.fields['email'].widget = EmailInput(attrs={'placeholder': 'Email'})
self.fields['email'].required = True
self.fields['email'].error_messages = {'required': 'Please enter your email'}
self.fields['first_name'].widget = TextInput(attrs={'placeholder': 'Forename'})
self.fields['first_name'].required = True
self.fields['first_name'].error_messages = {'required': 'Please enter your first_name'}
self.fields['last_name'].widget = TextInput(attrs={'placeholder': 'Surname'})
self.fields['last_name'].required = True
self.fields['last_name'].error_messages = {'required': 'Please enter your last_name'}
self.fields['password1'].widget = PasswordInput(attrs={'placeholder': 'Password'})
self.fields['password1'].required = True
self.fields['password1'].error_messages = {'required': 'Please enter your Password'}
self.fields['password2'].widget = PasswordInput(attrs={'placeholder': 'Confirm password'})
self.fields['password2'].required = True
self.fields['password2'].error_messages = {'required': 'Please confirm your Password'}
I also have the following in my views.py file:
class UserRegistrationView(FormView):
disallowed_url = ''
form_class = UserRegistrationForm
success_url = '/blog'
template_name = 'oauth/user/registration_form.html'
def registration_allowed(self):
return getattr(settings, 'REGISTRATION_OPEN', True)
def register(self, request):
if request.method == 'POST':
form = UserRegistrationForm(request.POST)
if form.is_valid():
new_user = form.save(commit=False)
new_user.set_password(form.cleaned_data['password1'])
new_user.save()
return render(request, 'blog/post/list.html', { 'new_user': new_user })
else:
return render(request, 'oauth/user/registration_form.html', { 'form': form })
def get_success_url(self, user=None):
return super(UserRegistrationView, self).get_success_url()
What's worrying:
It doesn't create a new user in the database to be logged in (should I expect to be able to see the newly created user in the general admin dashboard?)
It is able to sign in with the superuser! (I really don't get that one bit, like, seriously couldn't write that if I tried!)
Any help in where I may have gone wrong would be much appreciated!
You're confusing class based and function based views. Class based views don't have a method called "register"; yours will never be called.
Actually the method you have written is a complete function based view in its own right. Extract it from the class, remove the self parameter, and change the urlconf to call the function directly, and it should work.
Create a post method (or change the name of register to post) and add it to your class so that as_view() knows what to do with your class. then add it to your urlconf as a view.
class UserRegistrationView(FormView):
disallowed_url = ''
form_class = UserRegistrationForm
success_url = '/blog'
template_name = 'oauth/user/registration_form.html'
def post(self, request, *arg, **kwargs):
return self.register(request)
def registration_allowed(self):
return getattr(settings, 'REGISTRATION_OPEN', True)
def register(self, request):
if request.method == 'POST':
form = UserRegistrationForm(request.POST)
if form.is_valid():
new_user = form.save(commit=False)
new_user.set_password(form.cleaned_data['password1'])
new_user.save()
return render(request, 'blog/post/list.html', {'new_user': new_user})
else:
return render(request, 'oauth/user/registration_form.html', {'form': form})
def get_success_url(self, user=None):
return super(UserRegistrationView, self).get_success_url()
Then, in your urls:
urlpatterns = [
# . . .
url(r'^register_user/$', UserRegistrationView.as_view(), name='register_user'),
# . . .
]
You could also add a get method and use it to render your form if you are interested in keeping all of your form logic contained to one view class.