I am trying to test django.contrib.auth-based user signup view with django-nose, where an activation link is being sent to a new user:
def signup(request):
if request.method == 'POST':
user_form = SignUpForm(request.POST)
profile_form = ProfileForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save(commit=False)
user.is_active = False
user.save()
user.profile.user_type = profile_form['user_type'].data
user.save()
current_site = get_current_site(request)
subject = 'activation email'
message = render_to_string('registration/account_activation_email.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
user.email_user(subject, message)
return redirect('account_activation_sent')
else:
user_form = SignUpForm()
profile_form = ProfileForm()
return render(request, 'registration/signup.html', {
'user_form': user_form,
'profile_form': profile_form
})
Currently I use Django built-in email back-end, so that activation email is being sent to the server terminal.
I want to test the activation view which requires uid and token. Is there any way to access the email sent to the user? Is there any other way to test that?
Regenerating token in the test does not work, because hash value is generated using timestamp.
Related
I have a view to create a restaurant.
In the same view a user is also being created.
After the user creation, I have to sent a mail to the user with the link to reset the password.
My view looks like:
def create_restaurant(request):
form = RestaurantForm()
user_form = RestaurantUserForm()
if request.method == 'POST':
form = RestaurantForm(request.POST, request.FILES)
user_form = RestaurantUserForm(request.POST)
if form.is_valid() and user_form.is_valid():
#----user is saved here------
user_obj = user_form.save()
#----have to sent the mail here------
#-----restaurant is saved here-----
restaurant_obj = form.save()
restaurant_obj.user = User.objects.get(id=user_obj.id)
restaurant_obj.save()
messages.success(request, 'Restaurant Added Successfully.')
return redirect('create_restaurant')
context = {
"title": "Add restaurant",
"form": form,
"user_form": user_form
}
return render(request, "restaurant/restaurant.html", context)
I have implemented the password reset procedure using
urlpatterns = [
path('reset_password/',
auth_views.PasswordResetView.as_view(template_name="password_reset.html"),
name='password_reset'
),
path('reset_password_sent/',
auth_views.PasswordResetDoneView.as_view(template_name="password_reset_sent.html"),
name='password_reset_done'
),
path('reset/<uidb64>/<token>/',
auth_views.PasswordResetConfirmView.as_view(template_name="password_reset_form.html"),
name='password_reset_confirm'
),
path('reset_password_complete/',
auth_views.PasswordResetCompleteView.as_view(template_name="password_reset_done.html"),
name='password_reset_complete'
)]
How can I sent the email as mentioned above?
You can add a function to handle email sending like this
if request.method == 'POST':
form = RestaurantForm(request.POST, request.FILES)
user_form = RestaurantUserForm(request.POST)
if form.is_valid() and user_form.is_valid():
#----user is saved here------
user_obj = user_form.save()
#----have to sent the mail here------
ctx = {add all your data which you want to add in your email template}
send_user_email(ctx)
#-----restaurant is saved here-----
restaurant_obj = form.save()
restaurant_obj.user = User.objects.get(id=user_obj.id)
restaurant_obj.save()
messages.success(request, 'Restaurant Added Successfully.')
return redirect('create_restaurant')
and this is your function which is responsible to send emails
def send_user_email(ctx):
mail_subject = ctx['subject']
message = get_template('email_temp/user_notification.html').render(ctx)
to_email = ctx['user']
email = EmailMessage(
mail_subject,
message,
DEFAULT_FROM_EMAIL,
to=[to_email]
)
email.content_subtype = "html"
email.send(fail_silently=False)
return JsonResponse({'success':'success'})
you need to import some required things
from django.template.loader import get_template
from django.core.mail import EmailMessage
I'm currently working on building a multi-step registration form in Django. I followed the official documentation which can be seen here. Although the forms do not show any error, the user does not get created. Is there a problem I might be overlooking?
def signup_step_one(request):
if request.user.is_authenticated:
return HttpResponseRedirect(reverse('accounts:personal-signup'))
else:
if request.method == 'POST':
form = CustomUserCreationForm(request.POST)
if form.is_valid():
# collect form data in step 1
email = form.cleaned_data['email']
password = form.cleaned_data['password1']
# create a session and assign form data variables
request.session['email'] = email
request.session['password'] = password
return render(request, 'personal-signup-step-2.html', context={
'form': form,
"title": _('Create your personal account | Step 1 of 2'),
})
else:
form = CustomUserCreationForm()
return render(request, 'personal-signup-step-1.html', {
"title": _('Create your personal account | Step 1 of 2'),
'form': form,
})
def signup_step_two(request):
# create variables to hold session keys
email = request.session['email']
password = request.session['password']
if request.method == 'POST':
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.email = email
user.set_password(password)
user.first_name(form.cleaned_data['first_name'])
user.last_name(form.cleaned_data['last_name'])
user.save()
print('user created')
return HttpResponse('New user created')
else:
form = CustomUserCreationForm()
return render(request, 'personal-signup-step-2.html', {
"title": _('Create your account | Step 2 of 2'),
'form': form,
})
I noticed that the following line in signup_step_two function will always return the message "New user created" even if form is not valid:
return HttpResponse('New user created')
Put the above line inside the if statement. Also print form.errors in else statement or inside the template to check the problem.
Ex:
if form.is_valid():
# create the user
return HttpResponse('New user created')
else:
print(form.errors)
I know this question have been asked alot and most of the time its due to render or HttpResponse in the views.py, i double checked mine but the code looks good to me, dont know where the problem is.
This is a views.py file for a very basic django form but i can't get it to work
def register(request):
registered = False
if request.method == 'POST':
user_form = UserForm(data = request.POST)
profile_form = UserProfileInfoForm(data = request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_from.save()
user.set_password(user.password)
user.save()
profile = profile_form.save(commit = False)
profile.user = user
if 'profile_pic' in request.FILES:
profile.profile_pic = request.FILES['profile_pic']
profile.save()
registered = True
else:
return (user_form.errors,profile_form.errors)
else:
user_form = UserForm()
profile_form = UserProfileInfoForm()
return render(request,'basic_app/register.html',{'user_form': user_form,
'profile_form':profile_form,
'registered':registered})
You can not return (user_form.errors, profile_form.errors), since that is not a HttpResponse object. What response should the server return in that case.
Usually in case the form is invalid, the server will rerender the content. The form will, if you render it properly display the errors.
Note that in case the POST request was successful, you usually should redirect to implement the Post/Redirect/Get pattern [wiki]. You furthermore probably want to use a UserCreationForm [Django-doc]. This will set the password of the user in the correct way (with .set_password(..)), and run a password validator if you configured this.
You thus can rewrite your view as follows, but you probably should replace UserForm with UserCreationForm:
from django.shortcuts import redirect
def register(request):
if request.method == 'POST':
user_form = UserForm(data=request.POST)
profile_form = UserProfileInfoForm(data=request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_from.save(commit=False)
user.set_password(user.password)
user.save()
profile = profile_form.save(commit=False)
profile.user = user
if 'profile_pic' in request.FILES:
profile.profile_pic = request.FILES['profile_pic']
profile.save()
return redirect('name-of-view')
else:
user_form = UserForm()
profile_form = UserProfileInfoForm()
return render(
request,
'basic_app/register.html',
{'user_form': user_form, 'profile_form':profile_form })
So I'm making an email verification system but urlsafe_base64_decode is returning None instead of the pk.
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
username = form.cleaned_data['username']
password = form.cleaned_data['password']
subject = 'Activá tu mail'
current_site = get_current_site(request)
encoded_uid = urlsafe_base64_encode(force_bytes(user.pk)).decode()
message = render_to_string('firstpage/acc_active_email.html', {
'user': user,
'domain': current_site.domain,
'uid': encoded_uid,
'token': account_activation_token.make_token(user),
})
to_email = form.cleaned_data['email']
from_email = 'backend_email#gmail.com'
send_mail(subject, message, from_email, [to_email])
user.set_password(password)
user.save()
user_profile=UserProfile.objects.create(user=user)
#returns user objects if credentials are correct
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect('/')
return render(request, self.template_name, {'form': form})
Then the users clicks on a link and this is redirected to this function
def activate(request, uidb64=None, token=None):
uid = urlsafe_base64_decode(uidb64).decode()
user = User.objects.get(pk=uid)
if user is not None and account_activation_token.check_token(user, token):
user.is_active = True
user.save()
login(request, user)
# return redirect('home')
return HttpResponse('Thank you for your email confirmation. Now you can login your account.')
else:
print(user)
print(uid)
print(account_activation_token.check_token(user, token))
return HttpResponse('Activation link is invalid!')
uidb64 returns the same as urlsafe_base64_encode(force_bytes(user.pk)).decode() but urlsafe_base64_decode(uidb64).decode() returns None.
I'm using Django 2.1 by the way.
You need to use force_text to return a str object representing arbitrary object and keep the lazy objects, use this - force_text(urlsafe_base64_decode(uidb64))
For more reference you can visit the documentation
-https://docs.djangoproject.com/en/2.1/ref/utils/#django.utils.encoding.force_text
Hope this will help you.
This is very late. But for anyone like me that stumbles upon this and has the exact same problem.
Django 3 >>
The problem is on this line
'token': account_activation_token.make_token(user),
And the reason is because the user given here is a form instead of a proper user instance.
Therefore, for solution:
user_instance = request.user # if the user is logged in or
user_instance = get_user_model() # if you're using default user model or
user_instance = YourUserModel # if you are using a custom user model
Then:
'token': account_activation_token.make_token(user_instance),
Django==1.10.5. I have a problem RelatedObjectDoesNotExist
Views.py:
def register(request):
if request.method == 'POST':
user_form = UserRegistrationForm(request.POST)
if user_form.is_valid():
# Create a new user object but avoid saving it yet
new_user = user_form.save(commit=False)
# Set the chosen password
new_user.set_password(user_form.cleaned_data['password'])
# Save the User object
new_user.save()
# Create the user profile
profile = Profile.objects.create(user=new_user)
return render(request,
'account/register_done.html',
{'new_user': new_user})
else:
user_form = UserRegistrationForm()
return render(request, 'account/register.html', {'user_form': user_form})
and
#login_required
def edit(request):
if request.method == 'POST':
user_form = UserEditForm(instance=request.user,
data=request.POST)
profile_form = ProfileEditForm(instance=request.user.profile,
data=request.POST,
files=request.FILES)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
else:
user_form = UserEditForm(instance=request.user)
profile_form = ProfileEditForm(instance=request.user.profile)
return render(request, 'account/edit.html', {'user_form': user_form,
'profile_form': profile_form})
The problem is that:
profile_form = ProfileEditForm(instance=request.user.profile)
I have similar experience working on this particular exercise.
The error is coming right from code below
Profile_form = ProfileForm(request.POST, instance=request.user.profile)
We are trying to get "request.user.profile" not realizing "User" in the model doesn't have a "profile" but a Profile has a"User" . Therefore a better way to get the "profile":
profile = Profile(user=request.user)
Hence your edit method should look close to this:
#login_required
def edit(request):
profile = Profile(user=request.user)
if request.method == 'POST':
user_form = UserEditForm(instance=request.user,data=request.POST)
profile_form = ProfileEditForm(instance=profile,
data=request.POST,
files=request.FILES)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
messages.success(request, 'Profile updated successfully')
else:
messages.success(request, 'Error updating your profile')
user_form = UserEditForm(instance=request.user)
profile_form = ProfileEditForm(instance=profile)
return render(request,
'accounts/edit.html',
{'user_form': user_form,
'profile_form': profile_form})
Just to answer this question, this code is a snippet from the Django By Example book from the project Building a Social Website.
I encountered the same error when I clicked on the edit your profile link in the dashboard.
So, to solve this error, if you are logged in as a superuser, then go to the admin site of your project (url: localhost/admin/) and then under the Account heading, click on Profiles and click the Add profile link on the top right corner. Select the user from the dropdown, add the profile details and click save.
Now going back to the dashboard and clicking the edit your profile link should display the desired view.
I tried another alternative this scenario is that when we update our code we have some users that registered but not have a profile. I deleted the users and in admin and signed up with account it worked
but you will have a problem when logging with facebook