I would think the simplest thing to do is combine the get_object_or_404
and the user_can_access_c calls:
def get_allowed_c(request, cid):
c = get_object_or_404(C, pk=cid)
if user_can_access_c(request.user, c):
return c
else:
# not allowed; act as if user got the wrong url
raise Http404
@login_required
def foo(request, cid):
c = get_allowed_c(request, cid)
# Do whatever you want with c...
This means that each view function has a single line in common with the
others, just as it used to before your access checking.
--Ned.
Tim Chase wrote:
>> What I currently have to do is to define each view (such as to handle
>> "foo" above) as:
>>
>> @login_required
>> def foo(request, cid):
>> c = get_object_or_404(C, pk=cid)
>> if user_can_access_c(request.user, c):
>> # do something that's allowed
>> # ...
>> else:
>> # not allowed; act as if user got the wrong url
>> raise Http404
>>
>> ... and then I have to repeat this above codes for "bar" and "abc"
>> views. This feels rather excessive for me. Going with the don't-repeat-
>> yourself principle, I'd rather have a single place that does this
>> instead of sprinkling this codes for every view under /c/(?P<cid>\d
>> +)/...
>>
>> Any pointer you can give me would be greatly appreciated.
>>
>
> There are at least two suggestions that I can think of:
>
> In a similar situation, I found that the easiest way for me was
> to add a "get_allowable_objects_for_user" sort of method to the
> class in question:
>
> class C(Model):
> # class definition
> def get_allowed(self, user):
> # complex logic here
> if problems:
> raise SomeException
> return C.objects.filter(...)
>
> This may be overkill as it still requires some checking in each
> view function. However, for more complex access-control schemes,
> this can be useful to prevent awkward syntax from propagating
> across your views.py.
>
> Alternatively, you could use a double-dispatch sort of pattern.
> Your urls.py could pass in that second part
>
> /c/(?P<cid>\d+)/(P<whatever>foo|bar|abc) -> dispatch
>
> and then your view(s) would look something like:
>
>
> def foo(request, cid, c):
> # do something foo'ish with c
> def bar(request, cid, c):
> # do something bar'ish with c
> def abc(request, cid, c):
> # do something abc'ish with c
>
> action_mapping = {
> 'foo': foo,
> 'bar': bar,
> 'abc': abc,
> }
>
> @login_required
> def dispatch(request, cid, whatever):
> c = get_object_or_404(C, pk=cid)
>
> if user_can_access_c(request.user, c):
> action_mapping[whatever](request, cid, c)
> else:
> # not allowed; act as if user got the wrong url
> raise Http404
>
>
> That action_mapping bit can be cleaned up some if you keep a
> tight reign on your regexp for the definition of "whatever". In
> the above case, because we only explicitly allow "foo|bar|abc",
> it can be rewritten simply as
>
> if user_can_access_c(request.user, c):
> eval(whatever)(request, cid, c)
> else:
> raise Http404
>
> without the need for the action_mapping.
>
> Just a couple ideas for DRY'ing the code.
>
> -tim
>
>
>
>
>
>
>
> >
>
>
--
Ned Batchelder, http://nedbatchelder.com
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Django users" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---