As it seems that there is no longer any real opposition to this ticket (if there is, now would be the time to speak up) I'll go ahead and prepare a patch against the current trunk and get it uploaded to trac and see where we get to from there.
Hopefully I'll get a chance to take a look at this this week, I'll post a link to the trac ticket here once I've opened it. Cheers, Jordan On Friday, 2 November 2012 04:00:07 UTC+13, Andre Terra wrote: > > 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" <aaronm...@gmail.com<javascript:>> > 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 <tin...@gmail.com> 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 django-d...@googlegroups.com. >>>>> 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 >> django-d...@googlegroups.com<javascript:> >> . >> To unsubscribe from this group, send email to >> django-develop...@googlegroups.com <javascript:>. >> 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 view this discussion on the web visit https://groups.google.com/d/msg/django-developers/-/f-26zaSeKHgJ. To post to this group, send email to django-developers@googlegroups.com. To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.