Django CreateView ignoring get_success_url - django

I have the following view that works except that it is ignoring get_success_url(). It sends the user back to the same url for the form. The user is created. The view class is just an extended createview that I use in many other places without an issue.
class SignUpView(BSModalCreateView):
model = User
form_class = SignUpForm
success_message = 'Please check your email to complete the registration'
template_name = 'form_modal.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['heading'] = 'Create ID'
return context
def form_valid(self, form):
user = form.save(commit=False)
user.is_active = False
user.save()
# current_site = get_current_site(request)
current_site = '127.0.0.1:8000'
mail_subject = 'Activate your account.'
message = render_to_string('registration/confirm_email.html', {
'user': user,
# 'domain': current_site.domain,
'domain': '127.0.0.1:8000',
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': default_token_generator.make_token(user),
})
to_email = form.cleaned_data.get('email')
email = EmailMessage(
mail_subject, message, to=[to_email]
)
email.send()
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse('dashboard')
I have tried a bunch of different things t no avail but hope someone else can help.

I did some more testing and BSModal seems to be what is stopping this. I am not sure why but it is just easier and cleaner to just send a signal when a user is created. I created a field called is_self_registered on the user model and added the receiver:
#receiver(post_save, sender=User)
def send_activate_email(sender, instance, created, **kwargs):
user = User.objects.get(pk=instance.id)
if created and user.is_self_registered:
print('do email thing')
If one of the admins creates the ID it will be active. If self registration is used the id is not active.

Related

Generic detail view UserRegister must be called with either an object pk or a slug in the URLconf

I'm getting this error when trying to register to my to-do list web
Generic detail view UserRegister must be called with either an object pk or a slug in the URLconf.
views.py
class UserRegister(CreateView):
model = User
form_class = UserRegisterForm
template_name = 'users/form_register.html'
redirect_authenticated_user = True
success_url = reverse_lazy('tasks')
# Forbid logged in user to enter register page
def get(self, *args, **kwargs):
if self.request.user.is_authenticated:
return redirect('tasks')
return super(UserRegister, self).get(*args, **kwargs)
# Send email verification
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = UserRegisterForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.is_active = False
user.save()
current_site = get_current_site(request)
subject = 'Activate your account'
message = render_to_string('users/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('login')
else:
return self.form_invalid(form)
urls.py
urlpatterns = [
path('register/', UserRegister.as_view(), name='register'),
path('login/', UserLogin.as_view(), name='login'),
path('logout/', LogoutView.as_view(next_page='login'), name='logout'),
path('activate/<uidb64>/<token>/', ActivateAccount.as_view(), name='activate'),
]
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
Maybe it got something to do with the models.py? But to be honest I don't really know what else to put there.
Keep in mind I have two apps, the user app for registration and login and whatnot, and the tasks app for displaying tasks, creating, deleting task, etc.

How can I add uuid to url in urls.py django?

I have django app with authentication in it and email verification. When user is created activation email is sent with link inside of it, when user clicks this link is doesn't take him nowhere.
views.py
class customer_register(CreateView):
model = User
form_class = CustomerSignUpForm
template_name = 'authentication/customer_register.html'
def form_valid(self, form):
user = form.save()
user.token = str(uuid.uuid4())
subject = 'Verify your account | Zane'
message = f"http://127.0.0.1:8000/accounts/verify/{user.token}/"
recipient_list = [user.email]
send_mail(
subject,
message,
'from#example.com',
['to#example.com'],
fail_silently=False,
)
return redirect('/')
def activate(request, token):
try:
obj = models.User.objects.get(email_token = token)
obj.signup_confirmation = True
obj.save()
return HttpResponse('Your account is verified')
except Exception as e:
return HttpResponse('Invalid token')
urls.py
path('verify/<uuid:pk>/', views.activate, name='activate'),
models.py
...
token = models.CharField(max_length=200, blank=True)
signup_confirmation = models.BooleanField(default=False)
I wonder what do I need to put in my url to trigger my function?
I would rewrite your active view as a class. Here is an example:
class ActivateView(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
token = kwargs['pk']
try:
obj = User.objects.get(email_token = token)
obj.signup_confirmation = True
obj.save()
return HttpResponse('Your account is verified')
except Exception as e:
return HttpResponse('Invalid token')
urls.py
path('verify/<uuid:pk>/', ActivateView.as_view(), name='activate'),

Change URL Path for View Profile Page - Django

How would one go about creating a user-profile page that other users can view without being able to edit the profile unless they are the user?
The thing I'm trying to work out is how the url routing would work, is it best practice to store a user's profile on a profile/ or <user_id> page and then load in the individual user's data like recent posts using the username or id passed through the url?
Also would this be handled by the one view and template and just use {% if request.user == profile.user %} to display things like edit profile etc?
my problem is any user can edit for others there profiles when he edit url
for example my id is www.test.com/profile/44/ and other user have this id www.test.com/profile/40/
okay ,, now when i edit the link to be 40 not 44 i can access and edit the second user ! how to fix that
models.py :
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
email_confirmed = models.BooleanField(default=False)
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
def __str__(self):
return self.user
urls.py :
from django.urls import path
from blog_app.views import ProfileView
urlpatterns = [
path('profile/<int:pk>/', ProfileView.as_view(), name='profile'),
]
forms.py :
# Profile Form
class ProfileForm(forms.ModelForm):
# constructor of the UserForm, not Meta
def __init__(self, *args, **kwargs):
super().__init__(*args,**kwargs)
self.fields['username'].widget.attrs.update({'class':'form-control','placeholder':' Enter your username in English ','style': 'font-size:19px;text-align: center;'})
class Meta:
model = User
fields = [
'username',
'first_name',
'last_name',
'email',
]
views.py:
# Edit Profile View
class ProfileView(UpdateView):
model = User
form_class = ProfileForm
success_url = reverse_lazy('home')
template_name = 'user/commons/profile.html'
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.is_active = False # Deactivate account till it is confirmed
user.save()
current_site = get_current_site(request)
subject = 'Activate Your MySite Account'
message = render_to_string('user/emails/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)
messages.success(request, ('Please Confirm your new email to change email.'))
return redirect('login')
return render(request, self.template_name, {'form': form})
html page :
<button type="button" id="submit"> <a href="{% url 'profile' user.id %}" > edit profile info </a></button>
You can override the get_object() method to always return the currently logged on user from request.user, then you will not need to provide "pk" variable in your path.
Implement get_object() in your view
class ProfileView(UpdateView):
model = User
form_class = ProfileForm
success_url = reverse_lazy('home')
template_name = 'user/commons/profile.html'
def get_object(self, queryset=None):
return self.request.user
Then configure the path without pk
urlpatterns = [
path('profile/me/', ProfileView.as_view(), name='profile'),
]
Note that you should use login_required() decorator or LoginRequiredMixin on that view to avoid anonymous users accessing this view.

Django registration with confirmation email, error: save() got an unexpected keyword argument 'commit'

I'm trying to create confirm email system, bu I got the same error as in title, anyone know how to solve it?
class StudentSignUpView(CreateView):
model = User
form_class = StudentSignUpForm
template_name = 'registration/signup_form.html'
def form_valid(self, form, **kwargs):
user = form.save(commit=False)
user.is_active = False
user.save()
current_site = get_current_site(self.request)
mail_subject = 'Activate your account.'
message = render_to_string('core/acc_active_email.html', {
'user': user,'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
to_email = form.cleaned_data.get('email')
email = EmailMessage(
mail_subject, message, to=[to_email]
)
email.send()
return HttpResponse('Please confirm your email address to complete the registration')
forms.py
class Meta(UserCreationForm.Meta):
model = User
fields = ['username', 'email', 'password1', 'password2']
#transaction.atomic
def save(self):
user = super().save(commit=False)
user.is_student = True
user.save()
return user
The problem is that your save method in the form is not accepting any argument, and you are passing commit=False to it; You should add the argument to the save method:
def save(self, commit=True, *args, **kwargs):
user = super().save(commit=False, *args, **kwargs)
user.is_student = True
user.save()
return user
Generally, when you override a built-in method, you should keep the method signature as it was originally declared.

Django User Registration - not sure what is going wrong

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.