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 > > *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 > website: 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 > > 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 > > 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 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 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 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. > To post to this group, send email to [email protected]<javascript:> > . > To unsubscribe from this group, send email to > [email protected] <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/-/sWTyK1T42dMJ. 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.
