Handle various groups of users' profiles with django-userena - django

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

Related

Using a form wizard as Signup form django allauth

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.

Filter django admin by logged in user

I'm new to django.
I'm creating simple app in which I have users enter some data and view it later. I need to make django admin show to the user only the data she enter and non of the other users data.
Is it possible to change it to multiple admin pages?
Thank you
Store a reference to a user in your model.
models.py:
from django.db import models
from django.contrib.auth.models import User
class MyModel(models.Model):
user = models.ForeignKey(User)
... (your fields) ...
Force the current user to be stored in that field (when using admin)
Force any list of these objects to be (additionally) filtered by the current user (when using admin)
Prevent other users from editing (even though they can't see the object in the list they could access its change_form directly)
admin.py:
from django.contrib import admin
from models import MyModel
class FilterUserAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.user = request.user
obj.save()
def get_queryset(self, request):
# For Django < 1.6, override queryset instead of get_queryset
qs = super(FilterUserAdmin, self).get_queryset(request)
return qs.filter(created_by=request.user)
def has_change_permission(self, request, obj=None):
if not obj:
# the changelist itself
return True
return obj.user === request.user
class MyModelAdmin(FilterUserAdmin):
pass # (replace this with anything else you need)
admin.site.register(MyModel, MyModelAdmin)
If you have MyOtherModel with a foreign key "user" just subclass MyOtherModelAdmin from FilterUserAdmin in the same manner.
If you want certain superusers to be able to see anything, adjust queryset() and has_change_permission() accordingly with your own requirements (e.g. don't filter/forbid editing if request.user.username=='me').
In that case you should also adjust save_model() so that your editing doesn't set the user and thus "take away" the object from the previous user (e.g. only set user if self.user is None (a new instance)).
You'll have to save in the user to every item and query each item with that user as search criteria. You'll probably build a base model which all your other models will inherit from. To get you started take a look at row-level permissions in the admin.

Creating user profile pages in Django

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

Django admin - change permissions list

Is there any possibility to change permissions list in user edit page? I don't wan't to show all of permissions for example admin log entry or auth group etc.
How can I modify a main queryset to exclude some of it?
I got the idea from this topic, which also answer your question, but it's not that clear.
You have to overwrite the queryset of user permissions in the UserAdmin form used for visualization.
To do this, the easiest way is to create a subclass of UserAdmin and overwrite the get_form method:
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
class MyUserAdmin(UserAdmin):
def get_form(self, request, obj=None, **kwargs):
# Get form from original UserAdmin.
form = super(MyUserAdmin, self).get_form(request, obj, **kwargs)
if 'user_permissions' in form.base_fields:
permissions = form.base_fields['user_permissions']
permissions.queryset = permissions.queryset.filter(content_type__name='log entry')
return form
You can change the filter of your queryset for whatever you want:
Examples:
# Exclude admin and auth.
permissions.queryset = permissions.queryset.exclude(content_type__app_label__in=['admin', 'auth'])
# Only view permissions of desired models (Can be your models or Django's)
permissions.queryset = permissions.queryset.filter(content_type__model__in=['blog', 'post', 'user', 'group'])
After you create your class, you have to register your User model with your newly created Admin:
admin.site.unregister(User) # You must unregister first
admin.site.register(User, MyUserAdmin)
Edit:
I added comment from Maik Hoepfel, because this code made django crashed when creating new user.
You can do the same with the permission list in your Group edit page, but you have to create another Admin that extends from GroupAdmin, and change form.base_fields['user_permissions'] with form.base_fields['permissions']
Renato's answer is almost perfect. The Django Admin makes adding a user a two-step process with the same form, and his code fails with a KeyError for 'user_permissions' in the first step.
The fix is easy enough, just use the code below instead:
def get_form(self, request, obj=None, **kwargs):
form = super(MyUserAdmin, self).get_form(request, obj, **kwargs)
# adding a User via the Admin doesn't include the permissions at first
if 'user_permissions' in form.base_fields:
permissions = form.base_fields['user_permissions']
permissions.queryset = permissions.queryset.filter(content_type__name='log entry')
return form

Profile page getting acess to user object in Django

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. :)