On May 18, 2013, at 8:57 AM, Marc Tamlyn <marc.tam...@gmail.com> wrote:
> I'm going to resurrect this old thread as I'd like to get it resolved in some > fashion. > > I used to be very in favour of the class decorators approach. I've been using > an implementation of `@class_view_decorator(func)` for some time and it works > pretty well. That said my implementation at least was subject to a notable > flaw which is that if multiple parts of the hierarchy have the same decorator > applied to them then the check gets done twice. Mixins are much cleverer than > this because of MRO, so we avoid that problem. > > Mixins however have their own issues - it's "harder" (for some definition) to > ensure that all of your top-level permission checking happening in the > correct order. That said, I am certainly veering towards implementing this > using mixins (for each piece of functionality). > > I'd really like to have a look at Donald's implementation, sadly it seems to > no longer be on github. Do you still have then code somewhere, or can you > explain the implementation idea? I'm sure I have it somewhere, but knowing where is another thing all together ;) If I recall I made a mixin superclass that added an ``as_decorator()`` class function which functioned similarly to the ``as_view()`` function. It took a common entry point and generated a non class function based on that and returned it. As far as the actual mixins themselves I'd take a look at django-braces which has implementations of a lot of the decorators as mixins already they'd just need maybe some tweaking and then code added to allow turning them into actual decorators. > > Marc > > > On Thursday, 15 September 2011 22:44:39 UTC+2, Jacob Kaplan-Moss wrote: > Hi folks -- > I'd like to convert all the view decorators built into Django to be > "universal" -- so they'll work to decorate *any* view, whether a > function, method, or class. I believe I've figured out a technique for > this, but I'd like some feedback on the approach before I dive in too > deep. > > Right now view decorators (e.g. @login_required) only work on > functions. If you want to use a decorator on a method then you need to > "convert" the decorator using method_decorator(original_decorator). > You can't use view decorators on class-based views at all. This means > making a class-based view require login requires this awesomeness:: > > class MyView(View): > @method_decorator(login_required) > def dispatch(self, *args, **kwargs): > return super(MyView, self.dispatch(*args, **kwargs) > > This makes me sad. It's really counter-intuitive and relies on a > recognizing that functions and methods are different to even know to > look for method_decorator. > > #14512 proposes a adding another view-decorator-factory for decorating > class-based views, which would turn the above into:: > > @class_view_decorator(login_required) > class MyView(View): > ... > > This makes me less sad, but still sad. Factory functions. Ugh. > > I want @login_required to work for anything:: > > @login_required > class MyView(View): > ... > > class Something(object): > @login_required > def my_view(self, request): > ... > > @login_required > def my_view(request): > ... > > > Now, back in the day we somewhat had this: decorators tried to work > with both functions and methods. The technique turned out not to work > (see #12804) and was removed in [12399]. See > http://groups.google.com/group/django-developers/browse_thread/thread/3024b14a47f5404d > for the discussion. > > I believe, however, I've figured out a different technique to make > this work: don't try to detect bound versus unbound methods, but > instead look for the HttpRequest object. It'll either be args[0] if > the view's a function, or args[1] if the view's a method. This > technique won't work for any old decorator, but it *will* work (I > think) for any decorator *designed to be applied only to views*. > > I've written a proof-of-concept patch to @login_required (well, > @user_passes_test, actually): > > https://gist.github.com/1220375 > > The test suite passes with this, with one exception: > https://code.djangoproject.com/browser/django/trunk/tests/regressiontests/decorators/tests.py#L87. > I maintain that this test is broken and should be using RequestFactory > instead. > > Can I get some thoughts on this technique and some feedback on whether > it's OK to apply to every decorator built into Django? > > Jacob > > > > > > > > > > > > > > > > > > > > -- > You received this message because you are subscribed to the Google Groups > "Django developers" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to django-developers+unsubscr...@googlegroups.com. > To post to this group, send email to django-developers@googlegroups.com. > Visit this group at http://groups.google.com/group/django-developers?hl=en. > For more options, visit https://groups.google.com/groups/opt_out. > > ----------------- Donald Stufft PGP: 0x6E3CBCE93372DCFA // 7C6B 7C5D 5E2B 6356 A926 F04F 6E3C BCE9 3372 DCFA
signature.asc
Description: Message signed with OpenPGP using GPGMail