I've been trying to figure out the state of class based generic views
without success. (Though syndication views seems to be class based now
at least.)
If I figured out correctly the class based generic views does not land
on 1.2, so I was wondering are they planned to 1.3? Those are rather
important after all...
-- You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
On Tue, May 11, 2010 at 5:39 AM, Jari Pennanen <jari.penna...@gmail.com> wrote:
> I've been trying to figure out the state of class based generic views
> without success. (Though syndication views seems to be class based now
> at least.)
> If I figured out correctly the class based generic views does not land
> on 1.2, so I was wondering are they planned to 1.3? Those are rather
> important after all...
No - class-based views didn't land in 1.2. This is one of those
features that everyone agrees is a good idea, but someone needs to
actually write the code. Jacob made the most recent attempt at an
implementation that I'm aware of [1], but as the changelog indicates,
he hasn't made any recent updates.
Syndication-based views became class-based because of the good work of
Ben Firshman. He worked up a very good patch, submitted it in time for
the feature freeze, bugged a couple of core developers for reviews,
and it was committed.
Are class-based views planned for 1.3? Well, we haven't done any
formal planning for 1.3 yet, but I'm going to guess that the 1.3 high
priority feature list will essentially be "the features that got
dropped from 1.2", so in all likelihood, yes. However, that doesn't
mean that they will definitely be in 1.3 - someone still needs to do
the implementation. If you really want class based generic views, be
like Ben and make it happen -- show us the code!.
-- You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
Yes, well. I have been in slight assumption that the above code is the
one that will be merged. Though if it needs to be improved, I think
Jacobian could *list the problems in his implementation* so others can
try to improve on them, as he probably knows that code best.
From that point of view, I don't see a reason in rewriting the class
based generic-views as there is already Jacobian's take on it.
-- You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
> Yes, well. I have been in slight assumption that the above code is the
> one that will be merged. Though if it needs to be improved, I think
> Jacobian could *list the problems in his implementation* so others can
> try to improve on them, as he probably knows that code best.
> From that point of view, I don't see a reason in rewriting the class
> based generic-views as there is already Jacobian's take on it.
If you look at Jacob's code, you'll discover that Jacob's
implementation isn't complete. The edit views are still just stubs.
I've also seen comments about consistency between Jacob's
implementation and the class-based syndication views that are in
trunk.
That means there is still work to do, and someone needs to do it. If
you're going to volunteer to do the work, I don't think Jacob would
complain about getting assistance.
Yours,
Russ Magee %-)
-- You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
On 11 May 2010, at 01:37, Russell Keith-Magee wrote:
> Are class-based views planned for 1.3? Well, we haven't done any
> formal planning for 1.3 yet, but I'm going to guess that the 1.3 high
> priority feature list will essentially be "the features that got
> dropped from 1.2", so in all likelihood, yes. However, that doesn't
> mean that they will definitely be in 1.3 - someone still needs to do
> the implementation. If you really want class based generic views, be
> like Ben and make it happen -- show us the code!.
Oooh, class-based views.
This is something I've been thinking about a lot, and I'll probably dive into it at the Djangocon.eu sprints. Feel free to make a start Jari. ;)
Ben
-- You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
Things that people haven't really mentioned, but need addressing, that
we had to find solutions for:
* How to do redirects in class based views? See lines 71-86 and 166.
* How to decorate the __call__ method without doing a pointless
override of __call__ that just calls super so that you have something
to @decorate on top of. Check out the meta class on line 175. This
allows you to specify 'decorators = [login_required,
permission_required("polls.can_vote")]' on your subclass. I showed
this to Jacob at DjangoSki, and he seemed positive.
* How to decorate methods, when the decorator expects the first
argument to be request, and not self. See line 8. Ideally though,
Django's decorators would handle this, rather than forcing the use of
decorate_method_with on to the end users.
* How to deal with state and self. I have written an instantiator that
wraps the view class and instantiates a new instance of the class for
every request so that everything is thread safe. This works, but
agian, it would be nice if Django checked to see if the callable being
linked to a url route is a class, in which case it would handle the
instantiation of a new instance for every request. See line 188.
Excited to get this stuff in to 1.3!
_Nick_
On May 12, 1:16 pm, Ben Firshman <b...@firshman.co.uk> wrote:
> On 11 May 2010, at 01:37, Russell Keith-Magee wrote:
> > Are class-based views planned for 1.3? Well, we haven't done any
> > formal planning for 1.3 yet, but I'm going to guess that the 1.3 high
> > priority feature list will essentially be "the features that got
> > dropped from 1.2", so in all likelihood, yes. However, that doesn't
> > mean that they will definitely be in 1.3 - someone still needs to do
> > the implementation. If you really want class based generic views, be
> > like Ben and make it happen -- show us the code!.
> Oooh, class-based views.
> This is something I've been thinking about a lot, and I'll probably dive into it at the Djangocon.eu sprints. Feel free to make a start Jari. ;)
> Ben
> --
> You received this message because you are subscribed to the Google Groups "Django developers" group.
> To post to this group, send email to django-developers@googlegroups.com.
> To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
> For more options, visit this group athttp://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 django-developers@googlegroups.com.
To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
> On 11 May 2010, at 01:37, Russell Keith-Magee wrote:
>> Are class-based views planned for 1.3? Well, we haven't done any
>> formal planning for 1.3 yet, but I'm going to guess that the 1.3 high
>> priority feature list will essentially be "the features that got
>> dropped from 1.2", so in all likelihood, yes. However, that doesn't
>> mean that they will definitely be in 1.3 - someone still needs to do
>> the implementation. If you really want class based generic views, be
>> like Ben and make it happen -- show us the code!.
> Oooh, class-based views.
> This is something I've been thinking about a lot, and I'll probably dive into it at the Djangocon.eu sprints. Feel free to make a start Jari. ;)
I'd love to sprint on this at EDC too.
Regards,
David
-- You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
On 13 touko, 03:14, fitzgen <fitz...@gmail.com> wrote:
> * How to deal with state and self. I have written an instantiator that
> wraps the view class and instantiates a new instance of the class for
What about class method "instantiator"? It does have one extra nicety,
it does not need to be imported as one imports the view classes
already.
Then one could do: ``url(r'^path/$', ObjectView.instantiator(),
name="object_view")``
Thats mostly just syntactical sugar though, if it were class method I
would name it as create() or something...
But that is such a small detail at the moment it probably does not
matter.
-- You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
> * How to decorate the __call__ method without doing a pointless
> override of __call__ that just calls super so that you have
> something to @decorate on top of. Check out the meta class on line
> 175. This allows you to specify 'decorators = [login_required,
> permission_required("polls.can_vote")]' on your subclass. I showed
> this to Jacob at DjangoSki, and he seemed positive.
I personally don't like metaclasses if we can find another way. Here are some alternatives which use Plain Old Python:
1) from Python 2.6 we could use class decorators, and we could use the 'old style' MyClass = some_class_decorator(MyClass) until we move to Python 2.6.
2)
class Foo(View):
__call__ = some_decorator(View.__call__)
3) Add the decorators when you call 'instantiator' (which, by the way, I would rather call 'make_view' or something more specific). You would then have, *in views.py*:
- you can re-use MyViewClass with different decorators
- it protects us from changing the URLconf. The URLconf always
has a reference to the 'my_view' function, rather than
MyViewClass. Class-based views then remain an implementation
detail, just as they ought to be. It may well be that
a re-usable app provides some views and might switch
from class-based views to normal functions, and URLconfs
should be insulated from that change.
I don't like the idea of special-casing class based views anywhere, whether to cope with state or anything else. I think a view should still be 'a callable that takes a request and returns a response'. If that means we have to add an extra line to create a view function from a view class, so be it.
Given that it is going to be possible to use any/all of these whatever Django provides, I think I'm quite strongly in favour of 3a), and opposed to adding a metaclass which really doesn't add anything significant. Metaclasses add complications for people attempting to understand code, and should be used only when you really need them.
> * How to decorate methods, when the decorator expects the first
> argument to be request, and not self. See line 8. Ideally though,
> Django's decorators would handle this, rather than forcing the use
> of decorate_method_with on to the end users.
We already have 'django.utils.decorators.method_decorator' to cope with this. All attempts to have decorators that automatically adapt to functions/methods have failed. See my message here http://groups.google.com/group/django-developers/msg/f36976f5cfbcbeb3 It has some attachments with test cases that show how our previous attempt to do this didn't work in some situations.
One thing we could do to make it nicer for the end user is to create our own 'method' versions of all supplied decorators i.e:
cache_page_m = method_decorator(cache_page)
for every decorator we provide, so that people don't need to do that themselves.
However, this point may be moot given the discussion above.
Luke
-- "Mistakes: It could be that the purpose of your life is only to serve as a warning to others." (despair.com)
-- You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
On Thu, May 13, 2010 at 4:08 AM, Luke Plant <L.Plant...@cantab.net> wrote:
> On Thursday 13 May 2010 01:14:35 fitzgen wrote:
> > * How to decorate the __call__ method without doing a pointless
> > override of __call__ that just calls super so that you have
> > something to @decorate on top of. Check out the meta class on line
> > 175. This allows you to specify 'decorators = [login_required,
> > permission_required("polls.can_vote")]' on your subclass. I showed
> > this to Jacob at DjangoSki, and he seemed positive.
> I personally don't like metaclasses if we can find another way. Here
> are some alternatives which use Plain Old Python:
> 1) from Python 2.6 we could use class decorators, and we could use the
> 'old style' MyClass = some_class_decorator(MyClass) until we move to
> Python 2.6.
> 2)
> class Foo(View):
> __call__ = some_decorator(View.__call__)
> 3) Add the decorators when you call 'instantiator' (which, by the way,
> I would rather call 'make_view' or something more specific). You
> would then have, *in views.py*:
> - you don't need to worry about method decorators
> - you can re-use MyViewClass with different decorators
> - it protects us from changing the URLconf. The URLconf always
> has a reference to the 'my_view' function, rather than
> MyViewClass. Class-based views then remain an implementation
> detail, just as they ought to be. It may well be that
> a re-usable app provides some views and might switch
> from class-based views to normal functions, and URLconfs
> should be insulated from that change.
> I don't like the idea of special-casing class based views anywhere,
> whether to cope with state or anything else. I think a view should
> still be 'a callable that takes a request and returns a response'. If
> that means we have to add an extra line to create a view function from
> a view class, so be it.
> Given that it is going to be possible to use any/all of these whatever
> Django provides, I think I'm quite strongly in favour of 3a), and
> opposed to adding a metaclass which really doesn't add anything
> significant. Metaclasses add complications for people attempting to
> understand code, and should be used only when you really need them.
> > * How to decorate methods, when the decorator expects the first
> > argument to be request, and not self. See line 8. Ideally though,
> > Django's decorators would handle this, rather than forcing the use
> > of decorate_method_with on to the end users.
> We already have 'django.utils.decorators.method_decorator' to cope
> with this. All attempts to have decorators that automatically adapt
> to functions/methods have failed. See my message here
> http://groups.google.com/group/django-developers/msg/f36976f5cfbcbeb3 > It has some attachments with test cases that show how our previous
> attempt to do this didn't work in some situations.
> One thing we could do to make it nicer for the end user is to create
> our own 'method' versions of all supplied decorators i.e:
> cache_page_m = method_decorator(cache_page)
> for every decorator we provide, so that people don't need to do that
> themselves.
> However, this point may be moot given the discussion above.
> Luke
> --
> "Mistakes: It could be that the purpose of your life is only to
> serve as a warning to others." (despair.com)
> --
> You received this message because you are subscribed to the Google Groups
> "Django developers" group.
> To post to this group, send email to django-developers@googlegroups.com.
> To unsubscribe from this group, send email to
> django-developers+unsubscribe@googlegroups.com<django-developers%2Bunsubscr ibe@googlegroups.com>
> .
> 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 django-developers@googlegroups.com.
To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
> This is something I've been thinking about a lot, and I'll probably dive into it at the Djangocon.eu sprints.
I'll be there at the djangocon.eu sprints, but I can't find extra information about that. Are there actions I need to handle beforehand?
I'm used to Plone sprints and there's usually some "make sure you have svn access to x and y" stuff best handled *before* the sprint, that's why I'm asking :-)
-- You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
On Fri, May 14, 2010 at 9:12 AM, Reinout van Rees <rein...@vanrees.org> wrote:
...
> I'm used to Plone sprints and there's usually some "make sure you have svn
> access to x and y" stuff best handled *before* the sprint, that's why I'm
> asking :-)
If you have questions after that, let me know -- I'd be happy to
improve that page.
-- You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
Ah crap.. now you've done it.. now I want to be at the djangocon.eu
sprints too..
Why do all the fun things always happen at the same time..
I guess I could stay the thursday. and then go home on friday.
Ah well.. I'll have till monday to think about it.
On May 14, 4:27 pm, Jeremy Dunck <jdu...@gmail.com> wrote:
> On Fri, May 14, 2010 at 9:12 AM, Reinout van Rees <rein...@vanrees.org> wrote:
> ...
> > I'm used to Plone sprints and there's usually some "make sure you have svn
> > access to x and y" stuff best handled *before* the sprint, that's why I'm
> > asking :-)
> If you have questions after that, let me know -- I'd be happy to
> improve that page.
> --
> You received this message because you are subscribed to the Google Groups "Django developers" group.
> To post to this group, send email to django-developers@googlegroups.com.
> To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
> For more options, visit this group athttp://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 django-developers@googlegroups.com.
To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
> On Fri, May 14, 2010 at 9:12 AM, Reinout van Rees<rein...@vanrees.org> wrote:
> ...
>> I'm used to Plone sprints and there's usually some "make sure you have svn
>> access to x and y" stuff best handled *before* the sprint, that's why I'm
>> asking :-)
Yes, it does help :-) I've added a link to that page on the djangocon.eu wiki sprint page.
> If you have questions after that, let me know -- I'd be happy to
> improve that page.
That page is fine. The page linked from there that tells you how to set up an svn trunk django got me frowning a bit: "symlink django trunk into your system python". Ehm, I'd rather isolate it with virtualenv or buildout to keep trunk's stuff out of the rest of my django projects.
So: is that just a missing piece of documentation? Or is the virtualenv kind of isolation rarely done when developing on trunk?
Reinout
-- You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
On May 14, 2010, at 4:02 PM, Reinout van Rees <rein...@vanrees.org>
wrote:
> That page is fine. The page linked from there that tells you how to
> set up an svn trunk django got me frowning a bit: "symlink django
> trunk into your system python". Ehm, I'd rather isolate it with
> virtualenv or buildout to keep trunk's stuff out of the rest of my
> django projects.
> So: is that just a missing piece of documentation? Or is the
> virtualenv kind of isolation rarely done when developing on trunk?
I'm pretty sure it's just that it was written before virtualenv was
made. I should be updated. I use ve on dj dev often.
-- You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
On Thursday 13 May 2010 12:08:26 Luke Plant wrote:
> 3) Add the decorators when you call 'instantiator' (which, by the > way, I would rather call 'make_view' or something more specific). > You would then have, *in views.py*:
I had some more thoughts about this. One problem with applying the decorators after is if someone is re-using the class (e.g. subclassing), but forgets to apply some *necessary* decorators when creating the view from it. One work-around is that 'make_view' checks the class itself for a 'decorators' attribute, and applies them:
for f in getattr(viewclass, 'decorators', []): view = f(view)
return view
This would make it harder to forget, but would still allow subclasses to adjust the decorators that are used by default. It won't help in the case where people use the class directly in the URLconf, but I don't think that should be encouraged anyway.
Luke
-- "Oh, look. I appear to be lying at the bottom of a very deep, dark hole. That seems a familiar concept. What does it remind me of? Ah, I remember. Life." (Marvin the paranoid android)
On Thursday 27 May 2010 17:29:28 David Larlet wrote:
> Hello,
> We're working on this with Ben during djangocon.eu sprint [1]. Any > comment appreciated, still a work in progress though.
Looks cool. I think Jari's idea of a class method to instantiate the classes would be a great pattern to establish - something like an 'as_view' classmethod on the base class which returns a view function that uses the class:
The developer can choose whether to write 'MyClassView.as_view()' directly into the URLconf, or put a line into views.py like 'my_view = MyClassView.as_view()'
This will solve the thread safety issue, and doesn't require another import for a decorator, as Jari pointed out.
We could decide whether to apply decorators inside as_view() or __call__(). The argument for putting it in 'as_view' is that __call__ does some processing that you might want to skip entirely (e.g. the get_object() call - if we applied a 'cache_page' decorator, we wouldn't want the get_object() call to be made at all if there was a cache hit).
On that point, I think 'GenericView' should be split into 'ClassView' and 'GenericView'. The get_object() call is probably not a good thing to have on a base class.
Regards,
Luke
-- "Oh, look. I appear to be lying at the bottom of a very deep, dark hole. That seems a familiar concept. What does it remind me of? Ah, I remember. Life." (Marvin the paranoid android)
> On Thursday 27 May 2010 17:29:28 David Larlet wrote: >> Hello,
>> We're working on this with Ben during djangocon.eu sprint [1]. Any >> comment appreciated, still a work in progress though.
> Looks cool. I think Jari's idea of a class method to instantiate the > classes would be a great pattern to establish - something like an > 'as_view' classmethod on the base class which returns a view function > that uses the class:
> The developer can choose whether to write 'MyClassView.as_view()' > directly into the URLconf, or put a line into views.py like 'my_view = > MyClassView.as_view()'
> This will solve the thread safety issue, and doesn't require another > import for a decorator, as Jari pointed out.
> We could decide whether to apply decorators inside as_view() or > __call__(). The argument for putting it in 'as_view' is that __call__ > does some processing that you might want to skip entirely (e.g. the > get_object() call - if we applied a 'cache_page' decorator, we > wouldn't want the get_object() call to be made at all if there was a > cache hit).
We discussed that point with Jacob and it looks like it's easier to modify urlresolvers to create a new instance of the class when we detect it's a class, this should solve the thread safety issue. Do you see any drawback to this approach? That way we can declare decorators via a decorators' list [1] or directly in the class [2]. I'm not fond of the second way, decorating a decorator, but we can create decorators dedicated to class based views easily that way.
> On that point, I think 'GenericView' should be split into 'ClassView' > and 'GenericView'. The get_object() call is probably not a good thing > to have on a base class.
On Friday 28 May 2010 09:03:02 David Larlet wrote:
> > This will solve the thread safety issue, and doesn't require > > another import for a decorator, as Jari pointed out.
> > We could decide whether to apply decorators inside as_view() or > > __call__(). The argument for putting it in 'as_view' is that > > __call__ does some processing that you might want to skip > > entirely (e.g. the get_object() call - if we applied a > > 'cache_page' decorator, we wouldn't want the get_object() call > > to be made at all if there was a cache hit).
> We discussed that point with Jacob and it looks like it's easier to > modify urlresolvers to create a new instance of the class when we > detect it's a class, this should solve the thread safety issue. Do > you see any drawback to this approach?
I'm sure that will work. My main reluctance is using isinstance() when it isn't necessary, and having to change the definition of what a 'view' is when it isn't strictly necessary. (A view is no longer simply "a callable that takes a request and returns a response"). I guess this is partly about aesthetics, and I know practicality beats purity, but:
There might also be the following practical disadvantages when it comes to the API we encourage.
If the recommended usage is to do: urlpatterns = ... (r'something/', MyClassView) ...
then it would be easy to accidentally do `MyClassView()`, and it would appear to work fine, until you later get thread safety issues. Also, if you want to pass arguments to the constructor, you would most naturally do `MyClassView(somearg=something)`, and again it would appear to work.
If, however, we encouraged `MyClassView.as_view()` from the start, we can cope with constructor arguments more easily - it changes to `MyClassView.as_view(somearg=something)`.
(Either way, it would still be possible to pass in MyClassView() and get thread safety problems, but it's about making mistakes less natural).
Of course, if we want to use dotted path syntax in URLconfs - "path.to.MyClassView" - rather than imports, then we would *need* to have the isinstance() check to be able to cope with it at all. My response to that is: my preference would be that the use of class based views should remain an implementation detail, and as far as the URLconf is concerned, views.py should be exporting a ready-to-use callable not the class. (The class is exported for the purpose of other people subclassing, or passing their own constructor arguments, not for direct use in the URLconf).
There is also the issue of what to do when you need to add a decorator to someone else's view function. As a developer, I shouldn't have to know that class based views even *exist*, let alone how to use them, if I'm just a client - I should *always* be able to say:
from someapp.views import some_view_function my_view_function = login_required(some_view_function)
But if someapp.views has only exported SomeClassView and not some_view_function, I now have to do something different.
Given that, for many Django apps, the view functions are part of the public API that needs to be exported (i.e. hooked into people's URLconfs or wrapped for re-use), I think it would be good to encourage practices which will lead to stable and consistent APIs, and so *not* allow or encourage classes to be used directly in the URLconf.
Regards,
Luke
-- "Oh, look. I appear to be lying at the bottom of a very deep, dark hole. That seems a familiar concept. What does it remind me of? Ah, I remember. Life." (Marvin the paranoid android)
This is a bit of a tricky thing to discuss since we've been talking about this IRL at the sprints, and also on the list. I'll try to sum up where we are now, but if anything isn't clear, ask.
We're currently working towards URLpatterns of the form::
('...', SomeView)
i.e. passing a class directly, which would be instantiated implicitly then called.
The reason we're trying it this way is thread safety: if a view is a class, then people *will* store state on self. So if we have single instances in views like we do now, then we're giving folks enough rope to hang themselves. By having each request get a fresh instance we avoid that problem.
The other alternative we discussed was having the base view class do something with threadlocals to make sure state saved on self is threadsafe. I vetoed that because I hate threadlocals :)
On Fri, May 28, 2010 at 3:41 PM, Luke Plant <L.Plant...@cantab.net> wrote: > I'm sure that will work. My main reluctance is using isinstance() > when it isn't necessary, and having to change the definition of what a > 'view' is when it isn't strictly necessary. (A view is no longer > simply "a callable that takes a request and returns a response").
I *am* a bit worried by this -- I'm not sure redefining the definition of "view" is such a good idea. "A view is a callable or a class with callable instances" isn't nearly as simple and nice a recommendation.
> If, however, we encouraged `MyClassView.as_view()` from the start, we > can cope with constructor arguments more easily - it changes to > `MyClassView.as_view(somearg=something)`.
My only real objection here is that `as_view` is just a bunch of boilerplate::
As for accepting extra __init__ arguments: I specifically *don't* want to allow this (at least easily) because I want to encourage subclassing as the "correct" way of extending views. Yes, this means a slight loss of flexibility, but it also means that we're forcing people into a more extensible and fuure-proof way of coding, and that's a good thing.
> (Either way, it would still be possible to pass in MyClassView() and > get thread safety problems, but it's about making mistakes less > natural).
... and either way it's pretty easy to issue a warning if you've subclassed ``django.views.View`` (my proposed name for the view base class) and re-used it for multiple requests.
> There is also the issue of what to do when you need to add a decorator > to someone else's view function.
Again, I want to encourge "subclass it" as the correct answer here.
> Given that, for many Django apps, the view functions are part of the > public API that needs to be exported (i.e. hooked into people's > URLconfs or wrapped for re-use), I think it would be good to encourage > practices which will lead to stable and consistent APIs, and so *not* > allow or encourage classes to be used directly in the URLconf.
I think we're in agreement here -- we're both trying to avoid view-ish stuff in the URLconfs (a la the old way we used to do generic views with dicts in urls.py).
Having played with it for a few years now, though, I'm finding subclassing is really the best way to make this happen.
So reusable apps instead of exporting functional views export class-based ones; users who want to re-use them import, subclass, and extend.
If a class-based view by definition is instantiated on each request, we get a couple of neat things. For example, storing state on self.
Storing state on self makes things a heck of a lot easier. We are going to create a "View" and a "ResourceView". A View just renders a template, but a ResourceView has some kind of resource attached to it (model instance, QuerySet, whatever). On View, this would be the get_context() signature (where args and kwargs are from the URL):
We would have to redefine all the methods which require the resource. It seems neater to store it on self.
We have solved accidentally instantiating the view by raising an exception if a View instance is called twice. Of course, people who understand the threading issues are free to create their own class-based views.
I like this method because of its transparency. I fear having to explain as_view() in the documentation. Thread problems are hard to understand.
Ben
On 28 May 2010, at 16:51, Jacob Kaplan-Moss wrote:
> This is a bit of a tricky thing to discuss since we've been talking > about this IRL at the sprints, and also on the list. I'll try to sum > up where we are now, but if anything isn't clear, ask.
> We're currently working towards URLpatterns of the form::
> ('...', SomeView)
> i.e. passing a class directly, which would be instantiated implicitly > then called.
> The reason we're trying it this way is thread safety: if a view is a > class, then people *will* store state on self. So if we have single > instances in views like we do now, then we're giving folks enough rope > to hang themselves. By having each request get a fresh instance we > avoid that problem.
> The other alternative we discussed was having the base view class do > something with threadlocals to make sure state saved on self is > threadsafe. I vetoed that because I hate threadlocals :)
> On Fri, May 28, 2010 at 3:41 PM, Luke Plant <L.Plant...@cantab.net> wrote: >> I'm sure that will work. My main reluctance is using isinstance() >> when it isn't necessary, and having to change the definition of what a >> 'view' is when it isn't strictly necessary. (A view is no longer >> simply "a callable that takes a request and returns a response").
> I *am* a bit worried by this -- I'm not sure redefining the definition > of "view" is such a good idea. "A view is a callable or a class with > callable instances" isn't nearly as simple and nice a recommendation.
>> If, however, we encouraged `MyClassView.as_view()` from the start, we >> can cope with constructor arguments more easily - it changes to >> `MyClassView.as_view(somearg=something)`.
> My only real objection here is that `as_view` is just a bunch of boilerplate::
> As for accepting extra __init__ arguments: I specifically *don't* want > to allow this (at least easily) because I want to encourage > subclassing as the "correct" way of extending views. Yes, this means a > slight loss of flexibility, but it also means that we're forcing > people into a more extensible and fuure-proof way of coding, and > that's a good thing.
>> (Either way, it would still be possible to pass in MyClassView() and >> get thread safety problems, but it's about making mistakes less >> natural).
> ... and either way it's pretty easy to issue a warning if you've > subclassed ``django.views.View`` (my proposed name for the view base > class) and re-used it for multiple requests.
>> There is also the issue of what to do when you need to add a decorator >> to someone else's view function.
> Again, I want to encourge "subclass it" as the correct answer here.
>> Given that, for many Django apps, the view functions are part of the >> public API that needs to be exported (i.e. hooked into people's >> URLconfs or wrapped for re-use), I think it would be good to encourage >> practices which will lead to stable and consistent APIs, and so *not* >> allow or encourage classes to be used directly in the URLconf.
> I think we're in agreement here -- we're both trying to avoid view-ish > stuff in the URLconfs (a la the old way we used to do generic views > with dicts in urls.py).
> Having played with it for a few years now, though, I'm finding > subclassing is really the best way to make this happen.
> So reusable apps instead of exporting functional views export > class-based ones; users who want to re-use them import, subclass, and > extend.
> Jacob
> -- > You received this message because you are subscribed to the Google Groups "Django developers" group. > To post to this group, send email to django-developers@googlegroups.com. > To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com. > For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
I know that is just moving the boilerplate around, but it is giving a consistent interface. If some code in a re-usable app moves from normal views to class based views, they will have to do something like this *anyway* for backwards compatibility.
But I can see that if subclassing is the default way of re-using, then exporting these functions gives multiple options about how they should be re-used, which you are wanting to avoid.
> > There is also the issue of what to do when you need to add a > > decorator to someone else's view function.
> Again, I want to encourge "subclass it" as the correct answer here.
In that case, I guess it would be good to make this hard to do wrong, by providing helpers that add the decorator to the right end of the list of decorators.
Regards,
Luke
-- "Oh, look. I appear to be lying at the bottom of a very deep, dark hole. That seems a familiar concept. What does it remind me of? Ah, I remember. Life." (Marvin the paranoid android)
Luke, you're absolutely right that changing the definition of a view is a bad idea, it just seemed the best solution then.
But don't worry, we've changed our minds again! If __call__() creates a copy of self and calls methods on the copy, as far as I can see it solves all our problems. No boilerplate, and it's really hard to make it unsafe thread-wise.
> I know that is just moving the boilerplate around, but it is giving a > consistent interface. If some code in a re-usable app moves from > normal views to class based views, they will have to do something like > this *anyway* for backwards compatibility.
> But I can see that if subclassing is the default way of re-using, then > exporting these functions gives multiple options about how they should > be re-used, which you are wanting to avoid.
>>> There is also the issue of what to do when you need to add a >>> decorator to someone else's view function.
>> Again, I want to encourge "subclass it" as the correct answer here.
> In that case, I guess it would be good to make this hard to do wrong, > by providing helpers that add the decorator to the right end of the > list of decorators.
> Regards,
> Luke
> -- > "Oh, look. I appear to be lying at the bottom of a very deep, dark > hole. That seems a familiar concept. What does it remind me of? Ah, > I remember. Life." (Marvin the paranoid android)
> -- > You received this message because you are subscribed to the Google Groups "Django developers" group. > To post to this group, send email to django-developers@googlegroups.com. > To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com. > For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
> Luke, you're absolutely right that changing the definition of a view is a bad idea, it just seemed the best solution then.
> But don't worry, we've changed our minds again! If __call__() creates a copy of self and calls methods on the copy, as far as I can see it solves all our problems. No boilerplate, and it's really hard to make it unsafe thread-wise.
> > I know that is just moving the boilerplate around, but it is giving a
> > consistent interface. If some code in a re-usable app moves from
> > normal views to class based views, they will have to do something like
> > this *anyway* for backwards compatibility.
> > But I can see that if subclassing is the default way of re-using, then
> > exporting these functions gives multiple options about how they should
> > be re-used, which you are wanting to avoid.
> >>> There is also the issue of what to do when you need to add a
> >>> decorator to someone else's view function.
> >> Again, I want to encourge "subclass it" as the correct answer here.
> > In that case, I guess it would be good to make this hard to do wrong,
> > by providing helpers that add the decorator to the right end of the
> > list of decorators.
> > Regards,
> > Luke
> > --
> > "Oh, look. I appear to be lying at the bottom of a very deep, dark
> > hole. That seems a familiar concept. What does it remind me of? Ah,
> > I remember. Life." (Marvin the paranoid android)
> > --
> > You received this message because you are subscribed to the Google Groups "Django developers" group.
> > To post to this group, send email to django-developers@googlegroups.com.
> > To unsubscribe from this group, send email to django-developers+unsubscribe@googlegroups.com.
> > For more options, visit this group athttp://groups.google.com/group/django-developers?hl=en.