I'm making a school records webapp. I want staff users to be able to view the user data pages for any pupil by going to the correct url, but without allowing pupils access to each others' pages. However I'm using the same view function for both urls.
I have a working @user_is_staff
decorator based on the existence of a user.staff
object. Pupil users have a user.pupil
object instead. These are discrete, naturally, as no user can have both a .staff
and a .pupil
entry.
urls.py
(r'^home/(?P<subject>[^/]+)/$', 'myproject.myapp.views.display_pupil')
(r'^admin/user/(?P<user>\d+)/(+P<subject>[^/]+)/$', 'myproject.myapp.views.display_pupil')
views.py
@login_required
def display_pupil(request, subject, pupil=None):
if pupil:
try:
thepupil = get_object_or_404(Pupil, id = pupil, cohort__school = request.user.staff.school)
except Staff.DoesNotExist:
return HttpResponseForbidden()
else:
thepupil = request.user.pupil
thesubject = get_object_or_404(Subject, shortname = subject)
# do lots more stuff here
return render_to_response('pupilpage.html', locals(), context_instance=RequestContext(request))
Doing it this way works, but feels very hacky, particularly as my '@user_is_staff' decorator has a more elegant redirect to a login page than the 403 error here.
What I don't know is how to apply the @user_is_staff
decorator to the function only when it has been accessed with the pupil
kwarg. There's a lot more code in the real view function, so I don't want to write a second one as that would be severely non-DRY.
Sounds like you want two separate views - one for a specific pupil and one for the current user - and a utility function containing the shared logic.
@login_required:
def display_current_pupil(request, subject):
thepupil = request.user.pupil
return display_pupil_info(request, subject, thepupil)
@user_is_staff
def display_pupil(request, subject, pupil):
thepupil = get_object_or_404(Pupil, id=pupil, cohort__school=request.user.staff.school)
return display_pupil_info(request, subject, thepupil)
def display_pupil_info(request, subject, thepupil):
thesubject = get_object_or_404(Subject, shortname=subject)
# do lots more stuff here
return render_to_response('pupilpage.html', locals(), context_instance=RequestContext(request))