To be honest django is terrific, but in order to be general enough it lacks some look and feel and other stylistics things. One of the problem with forms, which generally work great, is with multi selections. You can have an item list or a checkbox list, like in the 90s. I decided to build a widget to render in a nice fashion the multi-selection case. It took me more than expected, roughly an afternoon, but I run into various problem and I’d to hack a bit the widgets. One of the biggest problem was to access the model.object in the widget since i want to display more data than just the label. Another problem that stucked me for a while was the fact that with crispy form the widget_template overiding seems not to be working (issue here).
Since I want to write less code as possible, the ingredients are:
- use Class Based view
- use Model Forms
And the final solution I made allowed me to cut ~50% of the code. Less code you write less bug you make.
The code, once made, is not complex. However, getting there took some time. Let’s start from the view.
rewriting the get_context function is done for being able to pass a queryset to the form. This allows us to have two benefits:
- we are able to display in the form field only the data that we want and not the entire list of items present in the database
- we can pass the queryset into the widget part, usually widgets do not have access to the context
To do so, we have to modify a bit the Form
As you can see we set the queryset of a inner field and also to as widget.qs value. Note that the widget of the field is linked to the brand new widget I just made.
For the widget, I had to extend and overwrite the get_context function in order to load a specifc value from the context. This is a bit of hack, since widget should not know the request or context data, but I need it!
Finally, in the templates (that you see in the form variable) I made the bootstrap panels where I displayed the widget and other information (directly from the object).
The first template is pretty standard
The second one has a piece of code to load from the qs variable the correct item that is displayed within the widget.
To do so I had to create a filter to get the item from the list
I also add some JS to make the whole panel green when selected.
For full code write a comment here and I’ll provide it.
This is the result
- It works
- It’s (somehow) better than the plain one and quite reusable
- It took longer than expected to implement it