At first I wasn't sure about this hook, but after working with permissions in CBVs I can see how this would allow for much simpler code, especially when you're implementing a lot of subclassing. I tend to get carried away in writing mixins and base classes for my views, so yeah, I'm +1 on this too.
Cheers, AT -- Sent from my phone, please excuse any typos. -- On Nov 1, 2012 12:31 PM, "Aaron Merriam" <[email protected]> wrote: > Just wanted to put my +1 into this thread. I've been fighting for a clean > way to implement permissions in class based views and the 'init' method > would help my implementation be a lot more DRY. > > On Wednesday, October 31, 2012 12:42:33 PM UTC-6, Jordan Hagan wrote: >> >> Diedreik, >> >> Thanks for your comments - your solution seems similar to the one >> proposed by Meshy unless I'm missing something (https://gist.github.com/* >> *1957251 <https://gist.github.com/1957251>). It is good to see multiple >> people coming up with the same solution to the issue independently though >> as that to me is an indication that we're moving in the right direction. >> >> Meshy, >> >> Thanks for the link - the django-braces project looks useful - I'll >> probably start using that. >> >> I would love to get some input from a core developer (or two) on this to >> see where they stand. From where I'm sitting there seems to be a number of >> people working around this problem in more or less the same manner, and >> most of the arguments against haven't taken into >> consideration compatibility **with other mixins, already existing class >> methods, etc. >> >> I would be happy to put together a patch in a ticket on trac and do any >> other grunt work required to make this happen. >> >> Cheers, >> Jordan >> >> On Wednesday, 31 October 2012 22:57:28 UTC+13, Meshy wrote: >>> >>> Marc and I have been using a mixin to override `dispatch()` with this >>> functionality. He has an ongoing pull request on >>> django-braces<https://github.com/brack3t/django-braces/pull/8>with the >>> code. I hope this can be useful to some of you. >>> >>> Meshy. >>> >>> On Wednesday, October 31, 2012 9:49:26 AM UTC, Diederik van der Boor >>> wrote: >>>> >>>> Hi, >>>> >>>> Please allow me to add my €0.02. >>>> In a large project I've experienced a similar issue; and we solved it >>>> in a slightly different way. >>>> What we also noticed was: >>>> - overriding dispatch(), get() or post() wasn't good enough anymore. >>>> - the views need some initialization moment before their workflow (in >>>> get/post of the base classes) start. >>>> >>>> What we ended up with is this base class (simplified a bit): >>>> https://gist.github.com/**3985939 <https://gist.github.com/3985939> >>>> >>>> *I seriously propose having such init() function in the Django views.* >>>> Mind you, that took a heated debate in the organization I was contacted >>>> for, so please allow me to explain to context here. >>>> I think we've found a missing cornerstone in the way the class based >>>> views are structured, and there is an easy fix. >>>> >>>> *What is the problem with overriding dispatch()?* >>>> When overriding dispatch(), get() or post() the flow is always: >>>> >>>> def dispatch(self, request, *args, **kwargs): >>>> # my code here. >>>> return super(…).dispatch(request, *args, **kwargs) >>>> >>>> The same also applies to get() and post(). >>>> In other words, the last deriving class on top of the inheritance chain >>>> is always initializing first before it's base classes. >>>> It can't rely on a base class to do some initialization. >>>> >>>> With our permission check in the base class' dispatch() >>>> method, anything deriving from that effectively >>>> couldn't override dispatch() anymore because that would run before the >>>> permission check. >>>> >>>> *How does the init method fix this?* >>>> By doing a self.init() in the top-most dispatch() method, each class in >>>> the inheritance chain has a chance to fetch the objects it needs to have. >>>> >>>> That code can be written as: >>>> >>>> def init(self): >>>> super(..).init() >>>> # my code here. >>>> >>>> Now, the base class can initialize, then the deriving class. >>>> With a larger inheritance chain, this behavior becomes crucial. >>>> Each class can build upon what the other has prepared already. >>>> >>>> >>>> All of a sudden, we could do things like this: >>>> >>>> class PhotoListView(TabbedListView): >>>> """ >>>> Contents of an photo album; a list of photo's. >>>> """ >>>> model = Photo >>>> >>>> template_name = "photoalbum_album.html" >>>> permission_class = permissions.**PhotoAlbumViewPermission >>>> >>>> def init(self): >>>> super(PhotoListView, self).init() >>>> self.photoalbum = get_object_or_404(PhotoAlbum, >>>> pk=self.kwargs['pk']) # parent object that filters the list >>>> >>>> def get_queryset(self): >>>> return super(PhotoListView, self).get_queryset().in_album(** >>>> self.photoalbum) >>>> >>>> def get_context_data(self, **kwargs): >>>> context = super(PhotoListView, self).get_context_data(**** >>>> kwargs) >>>> context['photoalbum'] = self.photoalbum >>>> context['can_delete'] = self.is_authorized_for(** >>>> PhotoDeleteView) >>>> return context >>>> >>>> This is a list view for photo's, and it's limited to a current photo >>>> album. >>>> The alternative is making a DetailView, and putting the photo's >>>> somewhere in get_context_data() and thereby loose what the list view >>>> has to offer. >>>> Now we can just state it's a list view (which it is), and introduce the >>>> filter easily. >>>> >>>> Without the init() method, you're probably knotting that somewhere in >>>> the get_queryset() and get_context_data(), >>>> without having a clear path of that's happening. Thanks to the simple >>>> init() method is all remains clean. >>>> >>>> >>>> *Some background of our use-case* >>>> The project is made for health care and privacy must be fully >>>> guaranteed. >>>> Hence, all views have to implement a permission check, which we wanted >>>> to have in the base class. >>>> The only place to hook things up, was before the super call to >>>> dispatch(), otherwise the view already executed. >>>> >>>> At the same time, the permission check needs information from things >>>> like "self.object", and the URL kwargs. >>>> That's because the permission check is role based; clients only see >>>> their views, counselors may inspect their clients, etc.. >>>> Implementing the check half-way in the regular get() and post() >>>> workflow wasn't an option as it's easy to miss. >>>> >>>> With the init() method, we allow the view to initialize, and fetch all >>>> objects, so more sophisticated code can be performed afterwards. >>>> Currently the permission check still fetches the objects itself as >>>> well, which will likely change in the future when the checks have more >>>> role-based options. >>>> >>>> >>>> I hope this gives a clear explanation why such method would be >>>> beneficial to Django's class based views. >>>> >>>> Looking forward to your suggestions and response, >>>> >>>> Diederik >>>> >>>> >>>> -- >>>> linkedin: >>>> http://nl.linkedin.**com/in/vdboor<http://nl.linkedin.com/in/vdboor> >>>> website: http://www.edoburu.**nl/ <http://www.edoburu.nl/> >>>> >>>> >>>> Op 30 okt. 2012, om 22:44 heeft Jordan Hagan het volgende geschreven: >>>> >>>> I would really like to see something like Meshy's proposed solution >>>> implemented as this is an issue that I've run into a few times as well. >>>> >>>> Although I can appreciate TiNo's argument of: >>>> >>>> > self.request = request >>>> > ... >>>> >>>> This creates a problem for methods that are going to be used in the >>>> overridden dispatch method and the dispatched method that need access to >>>> these attributes as they will need to be passed in as a parameter: >>>> >>>> in dispatch: >>>> self.some_method(request, *args, **kwargs) >>>> >>>> in dispatched: >>>> self.some_method(self.request, *self.args, **self.kwargs) >>>> >>>> which is just really messy. >>>> >>>> In addition to this methods from other generic view mixins cannot be >>>> used in the overridden dispatch method as they expect these class >>>> attributes to be available - 'get_object' on SingleObjectMixin is a good >>>> example of this as it requires self.kwargs to function: >>>> >>>> https://github.com/django/**django/blob/master/django/** >>>> views/generic/detail.py#L34<https://github.com/django/django/blob/master/django/views/generic/detail.py#L34> >>>> >>>> The only options available to us are monkey patching or code >>>> duplication, neither of which offer a good solution to this problem. >>>> Generic views are great for reducing boilerplate in code, and adding a hook >>>> in this case would do just that. Without this hook I'm forced to add code >>>> like the following to each of my projects as a workaround https://gist. >>>> **github.com/3983252 <https://gist.github.com/3983252> >>>> >>>> Cheers, >>>> Jordan >>>> >>>> On Saturday, 17 March 2012 09:52:43 UTC+13, Mike Fogel wrote: >>>> >>>>> > I don't really see what difference another function makes. >>>>> Sayhttps://gist.github.com/**1957251is<http://gist.github.com/1957251is>implemented, >>>>> what makes: >>>>> > >>>>> > def prepare_view(self, request, *args, **kwargs): >>>>> > # the thing I want to do >>>>> > super(ClassName, self).prepare_view(request, *args, **kwargs) >>>>> > >>>>> > preferable over: >>>>> > >>>>> > def dispatch(self, request, *args, **kwargs): >>>>> > # the thing I want to do >>>>> > super(ClassName, self).dispatch(request, *args, **kwargs) >>>>> > >>>>> > ? >>>>> >>>>> https://gist.github.com/**1957251 <https://gist.github.com/1957251>would >>>>> allow: >>>>> >>>>> def prepare_view(self, request, *args, **kwargs): >>>>> super(ClassName, self).prepare_view(request, *args, **kwargs) >>>>> # the thing I want to do - can use self.request, self.args, >>>>> self.kwargs >>>>> >>>>> As things stand now, I don't know of a graceful manner to use >>>>> self.request in a http-method independent way. >>>>> >>>>> FWIW, I've ran into this restriction a number of times, including >>>>> today. If one of the core devs will nod approval on this, I'll open a >>>>> ticket and attach this gist to it. >>>>> >>>>> Cheers, >>>>> >>>>> Mike >>>>> >>>>> On Mar 4, 9:45 am, Tino de Bruijn <[email protected]> wrote: >>>>> > I don't really see what difference another function makes. >>>>> Sayhttps://gist.github.com/**1957251is<http://gist.github.com/1957251is>implemented, >>>>> what makes: >>>>> > >>>>> > def prepare_view(self, request, *args, **kwargs): >>>>> > # the thing I want to do >>>>> > super(ClassName, self).prepare_view(request, *args, **kwargs) >>>>> > >>>>> > preferable over: >>>>> > >>>>> > def dispatch(self, request, *args, **kwargs): >>>>> > # the thing I want to do >>>>> > super(ClassName, self).dispatch(request, *args, **kwargs) >>>>> > >>>>> > ? >>>>> > >>>>> > You'll still have a super call because otherwise you have to repeat >>>>> the >>>>> > >>>>> > self.request = request >>>>> > self.args = args >>>>> > self.kwargs = kwargs >>>>> > >>>>> > part of prepare_view. >>>>> > >>>>> > What is wrong with overriding dispatch and calling super? (Or not, >>>>> if you >>>>> > don't want to progress in the view) >>>>> > >>>>> > Tino >>>>> >>>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "Django developers" group. >>>> To view this discussion on the web visit https://groups.google.com/d/** >>>> msg/django-developers/-/**uYmm9IR6P7QJ<https://groups.google.com/d/msg/django-developers/-/uYmm9IR6P7QJ> >>>> . >>>> To post to this group, send email to [email protected]. >>>> To unsubscribe from this group, send email to django-develop...@** >>>> googlegroups.com. >>>> For more options, visit this group at http://groups.google.com/** >>>> group/django-developers?hl=en<http://groups.google.com/group/django-developers?hl=en> >>>> . >>>> >>>> >>>> -- > You received this message because you are subscribed to the Google Groups > "Django developers" group. > To view this discussion on the web visit > https://groups.google.com/d/msg/django-developers/-/Um5fZBppDqMJ. > 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-developers?hl=en. > -- You received this message because you are subscribed to the Google Groups "Django developers" 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-developers?hl=en.
