Discussion:
[Future feature?] Viewsets
(too old to reply)
Bertrand Bordage
2013-01-26 03:04:57 UTC
Permalink
Hi,

This is my first message here, though I am using Django every day since two
years.

Yesterday I read a Ruby on Rails tutorial and this gave me an idea of what
could IMO be a nice feature: viewsets.
I therefore started a tiny project, django-viewsets<https://github.com/BertrandBordage/django-viewsets> (djangonauts
have weird reflexes… ^^). *Everything is explained there.*

What do you think? Could this be an interesting feature? “The next level
of class-based views”? A *contrib* application?

Regards,
Bertrand
--
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-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
To unsubscribe from this group, send email to django-developers+***@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Anssi Kääriäinen
2013-01-26 06:48:07 UTC
Permalink
Post by Bertrand Bordage
Hi,
This is my first message here, though I am using Django every day since two
years.
Yesterday I read a Ruby on Rails tutorial and this gave me an idea of what
could IMO be a nice feature: viewsets.
I therefore started a tiny project, django-viewsets<https://github.com/BertrandBordage/django-viewsets> (djangonauts
have weird reflexes… ^^).  *Everything is explained there.*
What do you think?  Could this be an interesting feature?  “The next level
of class-based views”?  A *contrib* application?
I do like the idea. I have actually implemented a different version of
the same idea: https://github.com/akaariai/multiviews. The multiviews
uses some meta-programming to autogenerate the urls, and it doesn't
use Django's class based views at all. The code is just a proof of
concept.

But, the barrier for additions to contrib/core is high. At least, the
addition proposed should be wanted by a substantial portion of Django
users, and it should be obvious that it is the way to implement the
feature. For this feature there are multiple ways to implement
viewsets / multiviews and it isn't at all obvious if one of the ways
is better than the rest. Likely different use cases warrant different
implementations.

- Anssi
--
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-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
To unsubscribe from this group, send email to django-developers+***@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Amirouche B.
2013-01-26 10:49:34 UTC
Permalink
Héllo Bertrand,

Yesterday I read a Ruby on Rails tutorial and this gave me an idea of what
Post by Bertrand Bordage
could IMO be a nice feature: viewsets.
I therefore started a tiny project, django-viewsets<https://github.com/BertrandBordage/django-viewsets> (djangonauts
have weird reflexes… ^^). *Everything is explained there.*
What do you think? Could this be an interesting feature? “The next level
of class-based views”? A *contrib* application?
It's very interesting and it might be why a similar thing exists in the
admin but not pluggable yet.

There is a ticket for this issue:
https://code.djangoproject.com/ticket/16213

I made another implementation of this
https://github.com/django-composite/django-composite/blob/master/composite/urls.py

- It's named UrlCollection since it's a collection of urls...
- Support callable, views function and CBVs
- It's possible to provide a default application_namespace (see
https://code.djangoproject.com/ticket/11642) but overridable at include time
- It's also possible to nest UrlCollections (equivalent your ViewSets class)
- It's possible to inherit AdminSite and ModelAdmin from UrlCollection and
implement the missing methods/properties...

But there is no particular support of GCBV (ListView, CreateView...), it's
a good idea I will add it.

Please have a look at it, I'll do the same with multiviews and viewsets and
to try to advance the discussion further maybe merge the three of them ?
--
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-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
To unsubscribe from this group, send email to django-developers+***@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Anssi Kääriäinen
2013-01-26 12:47:59 UTC
Permalink
Post by Amirouche B.
Please have a look at it, I'll do the same with multiviews and viewsets and
to try to advance the discussion further maybe merge the three of them ?
Multiviews is just a proof of concept. If you see something nice in
the concept, then reuse that. Otherwise it is throwaway code.

- Anssi
--
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-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
To unsubscribe from this group, send email to django-developers+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
Visit this group at http://groups.google.com/group/django-developers?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Bertrand Bordage
2013-01-26 23:21:21 UTC
Permalink
Hello Anssi, Amirouche, and anyone else,

Glad to see I am not the only one that got this idea (nearly at the same
time, btw)!
Post by Amirouche B.
It's very interesting and it might be why a similar thing exists in the
admin but not pluggable yet.
https://code.djangoproject.com/ticket/16213
OK. I guess we discuss in this google group until we come up to some
design decisions, then write it to the ticket?


I made another implementation of this
Post by Amirouche B.
https://github.com/django-composite/django-composite/blob/master/composite/urls.py
Please have a look at it, I'll do the same with multiviews and viewsets and
Post by Amirouche B.
to try to advance the discussion further maybe merge the three of them ?
Excellent! I spent two hours reading the code of both multiviews and
composite. Here is what I understood:


What's in common between multiviews, composite, and viewsets:

- Views are grouped in a class.
- Each view is tied to an URL pattern.
- All URL patterns of a group of views are accessible using nearly the
same syntax: GroupOfViews.urls() for multiviews, url('',
include(GroupOfViews().urls())) for composite and url('',
include(GroupOfViews().urls)) for viewsets.



Multiviews
Pros:

- Simple.

Cons:

- Uses inspect to find views. Too "magic" IMO.
- Requires to define a form, specify the namespace and template names
(example: https://github.com/akaariai/multiviews/blob/master/views.py#L96
).
- The views defined are very simple reimplementations of GCBV; and of
course, not extensible.
- No GCBV support.



Composite
Pros:

- Powerful; a complete framework to the glory of Python (write less
HTML/CSS/JS, more Python!) and DRY.
- Views directly have name and path attributes to avoid writing them
inside urls.py.

Cons:

- Complex.
- Highly misleading names (especially Widget…).
- No application namespace detection.
- Can't be easily merged in Django (I know, composite was not designed
for this purpose).



Viewsets
Pros:

- Simple.
- Designed to be extensible (even though it could be better).
- Automatic application namespace based on model app_labels.
- PEP8 compliance and Python3 support ;o)

Cons:

- No function-based views support (could be fixed in two lines).
- Uses an awkward dict to define views, url names and patterns.



By the way, I really liked in *composite* the idea of setting url names and
patterns as class-based view attributes.
Maybe the best idea of all this discussion; could this become a core
feature, as well as "template_name" and "get_template_name"?


Thanks,
Bertrand
--
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-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
To unsubscribe from this group, send email to django-developers+***@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Amirouche B.
2013-01-28 06:08:47 UTC
Permalink
Post by Bertrand Bordage
- Views are grouped in a class.
- Each view is tied to an URL pattern.
- All URL patterns of a group of views are accessible using nearly the
same syntax: GroupOfViews.urls() for multiviews, url('',
include(GroupOfViews().urls())) for composite and url('',
include(GroupOfViews().urls)) for viewsets.
I am in favor of using the include('path', GroupOfUrls.url()) syntax
Multiviews
- Simple.
- Uses inspect to find views. Too "magic" IMO.
- Requires to define a form, specify the namespace and template names
https://github.com/akaariai/multiviews/blob/master/views.py#L96).
Those are what UrlCollection are meant for.
- The views defined are very simple reimplementations of GCBV; and of
course, not extensible.
- No GCBV support.
Composite
- Powerful; a complete framework to the glory of Python (write less
HTML/CSS/JS, more Python!) and DRY.
- Views directly have name and path attributes to avoid writing them
inside urls.py.
The part was dropped because a) it can be implemented in user code b) It's
not «relevant» in the composite framework c) path makes view bound to urls
which makes it impossible to add a view in different places (loose
coupling...) and it is not relevant to UrlCollection, UrlCollection is only
the urls.py file.
Post by Bertrand Bordage
- Complex.
Only the urls.py file is takes part in the UrlCollection feature
- Highly misleading names (especially Widget…).
this is not related to UrlCollection
- No application namespace detection.
- Can't be easily merged in Django (I know, composite was not designed
for this purpose).
Actually it is, but not this way.
Viewsets
- Simple.
- Designed to be extensible (even though it could be better).
- Automatic application namespace based on model app_labels.
- PEP8 compliance and Python3 support ;o)
- No function-based views support (could be fixed in two lines).
- Uses an awkward dict to define views, url names and patterns.
I think ViewSets is the nearest thing to what could be merged, thus we
should use it. Also the model app_labels detection is only relevant for
model based UrlCollections and I think we should provide one feature at a
time.

Also what do you think about nested UrlCollection (or nested GroupOfViews)
basically make it possible to include other GroupOfView in a GroupView
Post by Bertrand Bordage
By the way, I really liked in *composite* the idea of setting url names
and patterns as class-based view attributes.
No, it's not a good idea, see above.
Post by Bertrand Bordage
Maybe the best idea of all this discussion; could this become a core
feature, as well as "template_name" and "get_template_name"?
In composite what I do, is bound the *View classes to the GroupOfViews
class then instantiate the bound class so that user code can override which
view is instantiated this way it's possible to change templates easily.
Adding a hook in GroupOfViews to override templates for several Views is
prone to error.

It lakes tests and documentation of course. I'll try to do a push to
Viewsets something if you did not already do it. I think getting an
external app up and running is the best thing to do.

Regards
--
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-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
To unsubscribe from this group, send email to django-developers+***@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Anssi Kääriäinen
2013-01-28 10:36:18 UTC
Permalink
Let me explain my use case. I have some CRUD views for similarly
behaving objects, and also some additional views (history view for
example). The add, modify and delete views have shared logic. And of
course, there is shared logic between the objects.

So, I'd like to create a base generic view for these objects. I want
to have my generic view, the use case is somewhat specialised... If I
can create my generic view from scratch, then I know the view is going
to match my use case.

The single class - single view pattern doesn't work for this use case.
It isn't easy to have the shared functionality between objects +
shared functionality between add, modify and delete views. It is
possible, but the code wont look nice.

There are multiple ways to implement the view collection pattern. It
isn't at all obvious that there is one right way to do this. If it
turns out there is a best way to do view collections, then integrate
that into core. Or, if there is some shared functionality each
implementation needs to do, then that shared functionality should be
in core. This all assuming a sizeable portion of Django users actually
want to use view collections.

I know this answer isn't wanted... But testing different
implementations outside Django core/contrib is IMHO the right way to
go.

- Anssi
Post by Amirouche B.
   - Views are grouped in a class.
   - Each view is tied to an URL pattern.
   - All URL patterns of a group of views are accessible using nearly the
   same syntax: GroupOfViews.urls() for multiviews, url('',
   include(GroupOfViews().urls())) for composite and url('',
   include(GroupOfViews().urls)) for viewsets.
I am in favor of using the include('path', GroupOfUrls.url()) syntax
Multiviews
   - Simple.
   - Uses inspect to find views.  Too "magic" IMO.
   - Requires to define a form, specify the namespace and template names
   https://github.com/akaariai/multiviews/blob/master/views.py#L96).
Those are what UrlCollection are meant for.
   - The views defined are very simple reimplementations of GCBV; and of
   course, not extensible.
   - No GCBV support.
Composite
   - Powerful; a complete framework to the glory of Python (write less
   HTML/CSS/JS, more Python!) and DRY.
   - Views directly have name and path attributes to avoid writing them
   inside urls.py.
The part was dropped because a) it can be implemented in user code b) It's
not «relevant» in the composite framework c) path makes view bound to urls
which makes it impossible to add a view in different places (loose
coupling...) and it is not relevant to UrlCollection, UrlCollection is only
the urls.py file.
   - Complex.
 Only the urls.py file is takes part in the UrlCollection feature
   - Highly misleading names (especially Widget…).
 this is not related to UrlCollection
   - No application namespace detection.
   - Can't be easily merged in Django (I know, composite was not designed
   for this purpose).
Actually it is, but not this way.
Viewsets
   - Simple.
   - Designed to be extensible (even though it could be better).
   - Automatic application namespace based on model app_labels.
   - PEP8 compliance and Python3 support ;o)
   - No function-based views support (could be fixed in two lines).
   - Uses an awkward dict to define views, url names and patterns.
I think ViewSets is the nearest thing to what could be merged, thus we
should use it. Also the model app_labels detection is only relevant for
model based UrlCollections and I think we should provide one feature at a
time.
Also what do you think about nested UrlCollection (or nested GroupOfViews)
basically make it possible to include other GroupOfView in a GroupView
By the way, I really liked in *composite* the idea of setting url names
and patterns as class-based view attributes.
No, it's not a good idea, see above.
Maybe the best idea of all this discussion; could this become a core
feature, as well as "template_name" and "get_template_name"?
In composite what I do, is bound the *View classes to the GroupOfViews
class then instantiate the bound class so that user code can override which
view is instantiated this way it's possible to change templates easily.
Adding a hook in GroupOfViews to override templates for several Views is
prone to error.
It lakes tests and documentation of course. I'll try to do a push to
Viewsets something if you did not already do it. I think getting an
external app up and running is the best thing to do.
Regards
--
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-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
To unsubscribe from this group, send email to django-developers+***@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Bertrand Bordage
2013-01-28 19:08:05 UTC
Permalink
@Amirouche:
Yes, sorry, I compared all django-composite instead of UrlCollections only...

Also the model app_labels detection is only relevant for model based
UrlCollections and I think we should provide one feature at a time.
In django-viewsets, this is a feature of ModelViewSet. The basic ViewSet
has no app_label by default.
Let me explain my use case. I have some CRUD views for similarly
behaving objects, and also some additional views (history view for
example). The add, modify and delete views have shared logic. And of
course, there is shared logic between the objects.
So, I'd like to create a base generic view for these objects. I want
to have my generic view, the use case is somewhat specialised... If I
can create my generic view from scratch, then I know the view is going
to match my use case.
Of course, this is exactly why I designed this - one of my private
applications has a lot of models sharing the same views, and not only
simple CRUD views.
Using viewsets, this becomes:

class HistoryView(View):
[do something...]

class CustomModelViewSet(ModelViewSet):
excluded_views = ('create_view', 'update_view', 'delete_view')

def __init__(self, *args, **kwargs):
self.views['history_view'] = {
'view': HistoryView,
'pattern': r'history',
'name': 'history',
'kwargs': { custom view attributes and methods here },
}
super(self, CustomViewSet).__init__(*args, **kwargs)

from .models import Example

class ExampleViewSet(CustomModelViewSet):
model = Example

This syntax could be simplified (using namedtuple, for example), but this
is working.


The single class - single view pattern doesn't work for this use case.
It isn't easy to have the shared functionality between objects +
shared functionality between add, modify and delete views. It is
possible, but the code wont look nice.
Hmm, you mean that writing GCBV for a specific use is hard?

There are multiple ways to implement the view collection pattern. It
isn't at all obvious that there is one right way to do this. If it
turns out there is a best way to do view collections, then integrate
that into core. Or, if there is some shared functionality each
implementation needs to do, then that shared functionality should be
in core. This all assuming a sizeable portion of Django users actually
want to use view collections.
I know this answer isn't wanted... But testing different
implementations outside Django core/contrib is IMHO the right way to
go.
OK, so, discussion closed.

Regard,
Bertrand
--
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-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
To unsubscribe from this group, send email to django-developers+***@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Anssi Kääriäinen
2013-01-31 09:25:21 UTC
Permalink
Post by Bertrand Bordage
Post by Anssi Kääriäinen
I know this answer isn't wanted... But testing different
implementations outside Django core/contrib is IMHO the right way to
go.
OK, so, discussion closed.
My intention wasn't to stop discussion about this feature, just to say
that it is unlikely to get into Django until there is a proven way to
implement this feature. And by proven I mean there is a 3rd party app
that has enough users.

It might be that there isn't a single approach to this, and in that
case multiple different implementations outside core is the way to go.
If there is something common between most implementations, then core/
contrib is the right place for those shared bits.

Looking at the discussion history maybe finding those shared bits was
all you were trying to do...

So, what I want is:
- To use self of the view collection class to bind data to templates
(that is, one instance per request).
- To use self to call shared functionality between views. That is, I
want to implement both history_view() and the update_view() in the
same class, so that both of them can call shared methods.

If I understand this pattern correctly

class HistoryView(View):
[do something…]
class CustomModelViewSet(ModelViewSet):
excluded_views = ('create_view', 'update_view', 'delete_view')
def __init__(self, *args, **kwargs):
self.views['history_view'] = {
'view': HistoryView,
'pattern': r'history',
'name': 'history',
'kwargs': { custom view attributes and methods here },
}
super(self, CustomViewSet).__init__(*args, **kwargs)

here HistoryView and UpdateView can't share functionality?

I think we are aiming for different use cases, the viewset pattern
seems to be about tying together multiple existing views, while the
MultiViews pattern is about creating the views in a single class.

- Anssi
--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
To post to this group, send email to django-developers-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
Visit this group at http://groups.google.com/group/django-developers?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Amirouche Boubekki
2013-01-31 10:59:14 UTC
Permalink
Héllo Anssi,
Post by Anssi Kääriäinen
Post by Bertrand Bordage
Post by Anssi Kääriäinen
I know this answer isn't wanted... But testing different
implementations outside Django core/contrib is IMHO the right way to
go.
OK, so, discussion closed.
My intention wasn't to stop discussion about this feature,
Sorry, I'm busy so I was waiting for the weekend to answer to posts.
Post by Anssi Kääriäinen
just to say
that it is unlikely to get into Django until there is a proven way to
implement this feature. And by proven I mean there is a 3rd party app
that has enough users.
Yes...
Post by Anssi Kääriäinen
It might be that there isn't a single approach to this, and in that
case multiple different implementations outside core is the way to go.
If there is something common between most implementations, then core/
contrib is the right place for those shared bits.
Looking at the discussion history maybe finding those shared bits was
all you were trying to do...
Yes

To give a bit of background on my take on this, it was while experimenting
on a rewrite of the admin that
lead me to UrlCollection.

CompositeView is one part which deals with Composition inside a view and
another part
is UrlCollection which deals with urls and thus views. Both are not needed
for the admin
to work but since it's a rewrite I wanted to take the time to extract
interesting pieces that could
be reused outside of the admin. The other part of the admin that is not
extracted from the admin yet,
is a class that deals with Forms and Formsets so that both ForeignKey and
M2M can be created in one
page.

So it's likely to be a useful pattern...
Post by Anssi Kääriäinen
- To use self of the view collection class to bind data to templates
(that is, one instance per request).
I read one instance of «view collection» per request otherwise you break
thread safety

- To use self to call shared functionality between views. That is, I
Post by Anssi Kääriäinen
want to implement both history_view() and the update_view() in the
same class, so that both of them can call shared methods.
This can be achieved with inheritance, do you have an example of sharing
data between views
that can not be achieved with View init_kwargs ?

Actually first version of UrlCollection was binding UrlCollection made
available a property on every view part of it,
that was returning a new instance of UrlCollection when accessed... Thus it
was possible to do:

class MyView(View):

def get_queryset(self, *args, **kwargs):
return dict('queryset', self.collection.get_queryset())

But I stripped that because not efficient and not needed because I think
it's possible to do everything you need through init_kwargs.
Post by Anssi Kääriäinen
If I understand this pattern correctly
[do something…]
excluded_views = ('create_view', 'update_view', 'delete_view')
self.views['history_view'] = {
'view': HistoryView,
'pattern': r'history',
'name': 'history',
'kwargs': { custom view attributes and methods here },
}
super(self, CustomViewSet).__init__(*args, **kwargs)
here HistoryView and UpdateView can't share functionality?
Yes.
Post by Anssi Kääriäinen
I think we are aiming for different use cases, the viewset pattern
seems to be about tying together multiple existing views, while the
MultiViews pattern is about creating the views in a single class.
Can you describe or give an example of MultiView usage ? Here is an dull
example of UrlCollection<https://github.com/django-composite/example-app/blob/master/delicatewebizen/favorites/urls.py#L7>,
there not declarative API since it's meant to be the base for anything
fancier ;)

Also I still don't agree with the naming, except if I didn't understand
this part, those projects are dealing with views through defining urls for
them. So the Collection class should be UrlCollection or something not
ViewCollection or MultiView.

Regards,

Amirouche
--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
To post to this group, send email to django-developers-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
Visit this group at http://groups.google.com/group/django-developers?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Wim Feijen
2013-01-31 18:29:44 UTC
Permalink
Hi,

Just wanted to draw your attention to a proposal made by Zachary Voase,
which you might be unaware of. It has no code, but is just a proposal,
having a very clean api IMHO.

http://zacharyvoase.com/2013/01/22/django-objviews/

Cheers, Wim
Post by Bertrand Bordage
Hi,
This is my first message here, though I am using Django every day since
two years.
Yesterday I read a Ruby on Rails tutorial and this gave me an idea of what
could IMO be a nice feature: viewsets.
I therefore started a tiny project, django-viewsets<https://github.com/BertrandBordage/django-viewsets> (djangonauts
have weird reflexes… ^^). *Everything is explained there.*
What do you think? Could this be an interesting feature? “The next level
of class-based views”? A *contrib* application?
Regards,
Bertrand
--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
To post to this group, send email to django-developers-/JYPxA39Uh5TLH3MbocFF+G/***@public.gmane.org
Visit this group at http://groups.google.com/group/django-developers?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Continue reading on narkive:
Loading...