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.

Reply via email to