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.

Reply via email to