I am trying to implement a form wizard at the registration/signup process. I am using django-allauth for authentication and based on the docs and a previous question How to customize user profile when using django-allauth It describes how to add extra fields to the sign up form. I don't really see how I can override the default form to use a form wizard. One option I was considering is adding all the extra fields to the signup form then displaying section of the forms with ajax but I am not sure how to implement validation on the different sections. Any guidance or help on how to implement the registration step as a wizard would be greatly appreciated.
I recently did this by:
views.py
from allauth.account.forms import SignupForm
from allauth.account.utils import complete_signup
SIGNUP_FORMS = [('signup', SignupForm),
('profile', forms.UserProfileForm)]
TEMPLATES = {'signup': 'trips/forms/wizard_form.html',
'profile': 'trips/forms/wizard_form.html'}
class SignupWizard(SessionWizardView):
def get_template_names(self):
return [TEMPLATES[self.steps.current]]
def done(self, form_list, **kwargs):
for form in form_list:
if isinstance(form, SignupForm):
user = form.save(self.request)
complete_signup(self.request, user, settings.ACCOUNT_EMAIL_VERIFICATION, settings.LOGIN_REDIRECT_URL)
elif isinstance(form, forms.UserProfileForm):
userprofile = form.save(commit=False)
user = self.request.user
userprofile.user = user
userprofile.save()
return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL)
You can add as many forms as you want. In my case, the UserProfileForm is a ModelForm that creates a new UserProfile object with a one-to-one relationship to the User. Both objects are only saved after both forms are submitted successfully. The complete_signup function is from allauth and it does some cleanup and then logs the user in to the site.
I ended up implementing the Wizard from the client side using AngularJS Django-angular package and this library. After digging through the allauth signup view code, I figured out it already implemented an AjaxCapableProcessFormViewMixin
Implementing a wizard using client side code for the sign up process when using django-allauth is probably the best way to go since you can delay the successful redirection till all forms in the wizard are filled and also prevents splitting long signup forms into smaller forms.
Related
I built an application that uses REST apis to inject information into a huge already existing database for a company. The application is a web form that the user fills out. My application then serializes the user's responses into a json that it uses to send post requests to the existent db.
My Django app also is connected to a SQL Server db where it is saving the responses of the user into the fields that I created in my models.py.
Is there a better way to do this? It seems like I'm saving all the information twice! A waste of space.
I don't think you need anything in your models.py for this particular application. Personally I like the approach of letting the Form handle the saving process. You could do something like this:
import json
from django import forms
class MyForm(forms.Form):
field1 = forms.CharField()
field2 = forms.IntegerField()
...
def save(self):
json_data = json.dumps(self.cleaned_data)
# insert code here to send the data to your REST API
Your view can then simply call the form.save() method in your view, even though this form is not a ModelForm.
if request.POST:
form = MyForm(request.POST)
if form.is_valid():
form.save()
return redirect(success_url)
return render(request, 'form.html', {'form': form})
I have successfully implemented a way to create users belonging to different groups with userena using a different form for each signup url, inheriting the userena signup form and overriding the save method to include the user to a group or another.
For instance in my /brands/ urls I have:
url(r'^signup/$',
'userena.views.signup',
{'template_name': 'userena/signup_form_brands.html', 'signup_form': SignupFormBrands}
),
and in that form I have:
from userena.forms import SignupForm
from django.contrib.auth.models import Group
class SignupFormBrands(SignupForm):
def save(self):
# First save the parent form and get the user.
new_user = super(SignupFormBrands, self).save()
new_user.groups.add(Group.objects.get(name='Brands'))
return new_user
So I got what I needed with the batteries included in userena. But now I would like to keep using the included profile editing / viewing capabilities of userena but with 2 different kinds of profiles. I would like to create 2 different profile models, one for my default users and one for the brands. Then I want userena to be able to edit the right kind of profile model according to the user belonging to a group or another. I'm not sure how this works and how I could do it.
Edit: userena uses profile = user.get_profile()to edit the profile so I'm going to try to assign a different profile object by editing this class.
you can override User.get_profile by following code:
original_get_profile = User.get_profile
def get_profile(self):
if getattr(settings, 'AUTH_PROFILE_MODULE', None) != 'profiles.Profile':
return original_get_profile(self)
if not hasattr(self, '_profile_cache'):
self._profile_cache = self.profile
self.profile.user = self
return self._profile_cache
User.get_profile = get_profile
Put it somewhere in models.py file with your profiles.
code copied from here: http://pastebin.com/MP6bY8H9
I would like to add the mugshot in django userena to the initial registration form, along with username, password and email address. I did as said in the faq (http://docs.django-userena.org/en/latest/faq.html#how-do-i-add-extra-fields-to-forms) So now I have my own form that inherits the userena signup form. I also redefined the save method to save the new mugshot in the user's profile. But now I don't know how to make that field appear in the form. I could not find any example since userena uses a modelform that automatically renders it. In the same way I can add a text field in this form as forms.CharField I would like to know what I should use to render the mugshot?
Well it appears that it is quite easy, just follow the steps described in the userena FAQ to add some extra fields to forms and in the new forms.py put something along the lines:
from django import forms
from userena.forms import SignupForm
class SignupFormExtra(SignupForm):
avatar = forms.ImageField()
def save(self):
new_user = super(SignupFormExtra, self).save()
profile = new_user.get_profile()
profile.mugshot = self.cleaned_data['avatar']
profile.save()
return new_user
I'm a beginner in Django. I need to setup a website, where each user has a profile page. I've seen django admin. The profile page for users, should store some information which can be edited by the user only. Can anyone point me out how that is possible?. Any tutorial links would be really helpful. Also, are there any modules for django, which can be used for setting up user page.
You would just need to create a view that's available to an authenticated user and return a profile editing form if they're creating a GET request or update the user's profile data if they're creating a POST request.
Most of the work is already done for you because there are generic views for editing models, such as the UpdateView. What you need to expand that with is checking for authenticated users and providing it with the object that you want to provide editing for. That's the view component in the MTV triad that provides the behavior for editing a user's profile--the Profile model will define the user profile and the template will provide the presentation discretely.
So here's some behavior to throw at you as a simple solution:
from django.contrib.auth.decorators import login_required
from django.views.generic.detail import SingleObjectMixin
from django.views.generic import UpdateView
from django.utils.decorators import method_decorator
from myapp.models import Profile
class ProfileObjectMixin(SingleObjectMixin):
"""
Provides views with the current user's profile.
"""
model = Profile
def get_object(self):
"""Return's the current users profile."""
try:
return self.request.user.get_profile()
except Profile.DoesNotExist:
raise NotImplemented(
"What if the user doesn't have an associated profile?")
#method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
"""Ensures that only authenticated users can access the view."""
klass = ProfileObjectMixin
return super(klass, self).dispatch(request, *args, **kwargs)
class ProfileUpdateView(ProfileObjectMixin, UpdateView):
"""
A view that displays a form for editing a user's profile.
Uses a form dynamically created for the `Profile` model and
the default model's update template.
"""
pass # That's All Folks!
You can
create another Model for storing profile information about user
add AUTH_PROFILE_MODULE='yourprofileapp.ProfileModel' to settings.py
In profile editing view, allow only logged in users to edit their own profiles
example:
#login_required
def edit_profile(request):
'''
edit profile of logged in user i.e request.user
'''
You can also make sure that whenever new user is created the user's profile is also created using django's signals
Read about storing additional information about users from django documentation
I have a requirement where I have to register users first via email. So, I went with django-registraton and I managed to integrate tat module into my django project.
After a successful login, the page redirects to 'registration/profile.html'.
I need to get access to the user object which was used in the authentication.
I need this object to make changes to a model which holds custom profile information about my users. I have already defined this in my models.py
Here is the URL I am using to re-direct to my template..
url(r'^profile/$',direct_to_template,{'template':'registration/profile.html'}),
So my question is this... after login, the user has to be taken to a profile page that needs to be filled up.
Any thoughts on how I can achieve this?
I have set up something similar earlier. In my case I defined new users via the admin interface but the basic problem was the same. I needed to show certain page (ie. user settings) on first log in.
I ended up adding a flag (first_log_in, BooleanField) in the UserProfile model. I set up a check for it at the view function of my frontpage that handles the routing. Here's the crude idea.
views.py:
def get_user_profile(request):
# this creates user profile and attaches it to an user
# if one is not found already
try:
user_profile = request.user.get_profile()
except:
user_profile = UserProfile(user=request.user)
user_profile.save()
return user_profile
# route from your urls.py to this view function! rename if needed
def frontpage(request):
# just some auth stuff. it's probably nicer to handle this elsewhere
# (use decorator or some other solution :) )
if not request.user.is_authenticated():
return HttpResponseRedirect('/login/')
user_profile = get_user_profile(request)
if user_profile.first_log_in:
user_profile.first_log_in = False
user_profile.save()
return HttpResponseRedirect('/profile/')
return HttpResponseRedirect('/frontpage'')
models.py:
from django.db import models
class UserProfile(models.Model):
first_log_in = models.BooleanField(default=True, editable=False)
... # add the rest of your user settings here
It is important that you set AUTH_PROFILE_MODULE at your setting.py to point to the model. Ie.
AUTH_PROFILE_MODULE = 'your_app.UserProfile'
should work.
Take a look at this article for further reference about UserProfile. I hope that helps. :)