Development story for CBV FormViews using GET

110 views
Skip to first unread message

Kye Russell

unread,
Mar 8, 2019, 7:55:40 PM3/8/19
to django-d...@googlegroups.com
Hi,

Sometimes it is appropriate to for a HTML form to use the GET method for submission (usually search / filter forms).

My impression has always been that in order to build a FormView-based view that acts on GET data, you have to override a few methods on your class (which involves understanding how FormView works). Even as someone with a fairly good understanding of these classes, I sometimes have to reference a previously-written example to make sure I've got it right.

I am aware of the existence of django-filter[0] which takes care of this for you, however at times I find it hard to justify adding it to a project just to deal with this.

I have the following questions:

* Is my understanding of the current process correct, or is there an easier way that I've missed?
* Is this documented anywhere? I looked at the Django 'working with forms' documentation[1], and whilst it discusses the different scenarios in which you'd use GET vs POST, it does not seem to discuss implementations in a CBV context.
* Is there enough of a generic use-case where FormView / FormMixin / ProcessFormView could be altered to support this? Or are there subtleties / nuances in each implementation that make a generic solution hard to develop?

Sorry if this is the wrong avenue to discuss this. I am approaching it from the position of wanting to alter Django to better support this use case, but I'm aware that I may have just missed a Blessed method in the docs.

Kye



Adam Johnson

unread,
Mar 9, 2019, 9:09:52 AM3/9/19
to django-d...@googlegroups.com
 I find it hard to justify adding it to a project just to deal with this.

Why is it hard to justify adding it? django-filter is in the class of very stable django third party packages, and it's even maintained by Django fellow Carlton Gibson.

* Is my understanding of the current process correct, or is there an easier way that I've missed?

I'd say that's right. If you're finding you need to do too much customization on the view, it's also fine to write your own based on the generic View class or a FBV. CBV's can get complicated quickly because of all the individual methods.

Is this documented anywhere?

Sounds to me like you found all the relevant documentation. I'd also point out the unofficial docs site https://ccbv.co.uk/ by core developer Marc Tamlyn that aims to make Django's CBV's easier to understand, and the third party package http://django-vanilla-views.org/ by core developer Tom Christie that provides an alternative simpler CBV class tree that can be easier to customize.

* Is there enough of a generic use-case where FormView / FormMixin / ProcessFormView could be altered to support this? Or are there subtleties / nuances in each implementation that make a generic solution hard to develop?

For changing where the form data comes from, don't you just need to override get_form_kwargs as per https://github.com/django/django/blob/master/django/views/generic/edit.py#L35 ? Without really diving into the problem I can't see anything else that seems to need changing, having done this you're definitely in a better position to suggest a change :)
 

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/CANK-ykkMtxezA9cHN8jQ_czLn6OYtdDn6JYbjNgASyyqHH-aAw%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.


--
Adam

Luke Plant

unread,
Mar 14, 2019, 2:56:24 AM3/14/19
to django-d...@googlegroups.com

Hi Kyle,

My take would be this: What does the code look like if you don't use FormView but just write a function view? How does that compare to using a CBV? This may be the simpler method you are missing - if you are finding you are fighting with inherited functionality, just don't inherit it.

Luke

Carsten Fuchs

unread,
Mar 14, 2019, 3:51:03 AM3/14/19
to django-d...@googlegroups.com
Hello,

I'm not a Django contributor, just a user, but please allow me to express my opinion that CBVs are an extra layer of functionality that seems to have made it into the foreground attention since it was introduced, but I think that that is very unfortunate:

CBVs bring not only extra functionality, but also complexity. With that, they obscure the three-paths idea that is used in FBVs (no POST data, POST data that validates with errors and without). Yes, the three-paths method seems like a tedious pattern that must repeatedly be written by hand. But in my opinion, it clearly expresses a key concept that is very important for beginners to understand, especially as beginners that are new to Django often are new to web development as well.
Kyle seems to have experience with web development, but all the more his question is a prime example of that issue.
In my opinion, DRY is not above all. I've been using Django for years and have never found CBVs attractive but for a narrow range of use cases.

Personally, I think that both in examples, courses and the Django tutorials the focus should be on FBVs. Only then and only on this basis should CBVs be introduced, with an emphasis on how they emerged from FBVs.

Best regards,
Carsten


Am 14.03.19 um 07:56 schrieb Luke Plant:
> Hi Kyle,
>
> My take would be this: What does the code look like if you don't use FormView but just write a function view? How does that compare to using a CBV? This may be the simpler method you are missing - if you are finding you are fighting with inherited functionality, just don't inherit it.
>
> Luke
>
>
> On 09/03/2019 03:55, Kye Russell wrote:
>> Hi,
>>
>> Sometimes it is appropriate to for a HTML form to use the GET method for submission (usually search / filter forms).
>>
>> My impression has always been that in order to build a FormView-based view that acts on GET data, you have to override a few methods on your class (which involves understanding how FormView works). Even as someone with a fairly good understanding of these classes, I sometimes have to reference a previously-written example to make sure I've got it right.
>>
>> I am aware of the existence of django-filter[0] which takes care of this for you, however at times I find it hard to justify adding it to a project just to deal with this.
>>
>> I have the following questions:
>>
>> * Is my understanding of the current process correct, or is there an easier way that I've missed?
>> * Is this documented anywhere? I looked at the Django 'working with forms' documentation[1], and whilst it discusses the different scenarios in which you'd use GET vs POST, it does not seem to discuss implementations in a CBV context.
>> * Is there enough of a generic use-case where FormView / FormMixin / ProcessFormView could be altered to support this? Or are there subtleties / nuances in each implementation that make a generic solution hard to develop?
>>
>> Sorry if this is the wrong avenue to discuss this. I am approaching it from the position of wanting to alter Django to better support this use case, but I'm aware that I may have just missed a Blessed method in the docs.
>>
>> Kye
>>
>> [0]: https://github.com/carltongibson/django-filter
>> [1]: https://docs.djangoproject.com/en/2.1/topics/forms/
>>
>>
>> --
>> You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
>> To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com <mailto:django-develop...@googlegroups.com>.
>> To post to this group, send email to django-d...@googlegroups.com <mailto:django-d...@googlegroups.com>.
>> To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/CANK-ykkMtxezA9cHN8jQ_czLn6OYtdDn6JYbjNgASyyqHH-aAw%40mail.gmail.com <https://groups.google.com/d/msgid/django-developers/CANK-ykkMtxezA9cHN8jQ_czLn6OYtdDn6JYbjNgASyyqHH-aAw%40mail.gmail.com?utm_medium=email&utm_source=footer>.
>> For more options, visit https://groups.google.com/d/optout.
>
> --
> You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com <mailto:django-develop...@googlegroups.com>.
> To post to this group, send email to django-d...@googlegroups.com <mailto:django-d...@googlegroups.com>.
> To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/668e083b-d3c1-8a5b-989e-03a0a85d895a%40cantab.net <https://groups.google.com/d/msgid/django-developers/668e083b-d3c1-8a5b-989e-03a0a85d895a%40cantab.net?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout.

--
Dipl.-Inf. Carsten Fuchs
Industriegebiet 3 ℅ Rofu
55768 Hoppstädten-Weiersbach
https://www.cafu.de

Jamesie Pic

unread,
Mar 14, 2019, 4:26:59 AM3/14/19
to django-d...@googlegroups.com
Kyle, is it possible to show the code you are talking about ?

Jamesie Pic

unread,
Apr 18, 2019, 5:20:12 PM4/18/19
to django-d...@googlegroups.com
Hi Kye,

Sorry for mispelling your name above, but it's a really long thread and non-native. And I can tell, there's rarely a better way than discussing in foreign languages to make a nice little fool of myself xD This time I will share my story with CBV, a story with love, and code and aggressive design patterns in it. This is all because one of you consulting for yourlabs made a comment about my shitty JS code: it was non aggressive. I've been working that state of mind and then ...

The first violation I made to any bare common sense was to add support for magical getters ... now view.url can return the result of view.get_url()

... And then I went on breaking Python by adding support in the type as well ... now View.url can also return the result of View.get_url()

... At the price of thread safety, I guess I'm lucky it was always an easy fix "just use the right variable you're allowed to but keep on refactoring"

... And then it became even more obscure when the magical getter also was able to detect if {V,v}iew.get_url(view) would have not returned anything, but did set {V,v}iew.url as attribute ... now caching became absolutely free ...

... And then added a Controller in-between Model and its set of View ... now Django knows MVC and can generate object level menus with efficient permission management thanks to the Django permission backend that has so many plugins or whatever implementation you put to override per controller or view ...

... And then added a rich experience from out of the box templates because why not after all django-webpack-loader by @alihazemfarouk is dope to upgrade front end development workflow to a level like Python ...

... Don't ask what front-end framework cause what matters to me is the practice of an modular development workflow, not which JS framework ...

... All this because a friend of mine who didn't understand Django, didn't understand why we should hardcode menu HTML code, and cried in my laps for help to refactor for days, the first name for the Controller class was "Drycrud", do you imagine, instanciating a new Drycrud object ? Even more obscure. Well at least it's named Router for now but in its final version it needs to be called Controller because it sits between the Model and it's set of class Based views ...

... So the generic ListView for example is like:
class ListView(mixins.ListMixin, mixins.SearchMixin, mixins.FilterMixin,
mixins.TableMixin, mixins.ObjectsMixin, TemplateView):
def get_object_list(self):
if self.filterset:
self.object_list = self.filterset.qs
else:
self.object_list = self.queryset
if self.search_form:
self.object_list = self.search_form.get_queryset()
return self.object_list
def get_listactions(self):
return self.controller.get_menu('list_action', self.request)

The view.listactions variable allows a view to override programmatically what items the default list view template will propose for selected items. It takes the request object for permission checking which is pretty raw but turns out to just work: router.get_menu() returns a list of View classes of the same Controller (thus same Model in practice), for which view.has_perm() returns true. has_perm() is called once the view has been hydrated with the passed request object in view.request. Your high level code uses view.object instead of view.get_object(), because get_object() will already be called automatically as a magic getter....

As for get_object_list horror ... hopefully it's the only class in the whole crudlfap.views.generic that encapsulates this kind of coupling, but at the same time the coupling in there depends on what the parent mixins offer and that is quite tricky to get right, but at the end of the day it's just gluing the mixins together.

Please forgive this horror story from being loaded with absolutely non-impressive material:


Want to share more use cases with CBVs ? Reply to the list now !

Thanks for reading and have a great day ;)
Reply all
Reply to author
Forward
0 new messages