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
-~----------~----~----~----~------~----~------~--~---

Reply via email to