I have two problems that I am working on, both of which involve manipulating the set of objects listed in a form select.
The basics of this are that I have edited the __init__
method in the form, to give custom querysets, in this example matching the sessions available to choose to the day of the week (I’ve hardcoded the day of the week just for simplicity). The query also finds sessions that are available for “any” day (in this scheme the day int for “any” is “8” – cf Lennon and Macartney). This scheme uses ISO day ints:
form.fields['session'].queryset = Session.objects.filter(is_inactive=False).filter(Q(dayint=1)|Q(dayint=8))
This works pretty well, it finds all the sessions for “Monday” and “Any”, with the “Any” at the bottom due to the default ordering.
However, there are two bits of UI I’d like to finesse around this solution: inserting a break between “Monday” and “Any” sessions, and giving an indicator where no “day” sessions are found (I suppose that it is possible that there are no “Any” sessions, but that problem is solved with the “day” fix).
So, the select currently looks like:
<select name="session" class="form-control" title="" required id="id_session">
<option value="" selected>---------</option>
<option value="1">Monday 10:00</option>
<option value="2">Monday 13:00</option>
<option value="3">Monday 16:00</option>
<option value="4">Monday 19:00</option>
<option value="17">Anyday drop-in 12:30</option>
</select>
Or, where there are no “day” sessions:
<select name="session" class="form-control" title="" required id="id_session">
<option value="" selected>---------</option>
<option value="17">Anyday drop-in 12:30</option>
</select>
But what I’d prefer to do is something like:
<select name="session" class="form-control" title="" required id="id_session">
<option value="" selected>---------</option>
<option value="1">Monday 10:00</option>
<option value="2">Monday 13:00</option>
<option value="3">Monday 16:00</option>
<option value="4">Monday 19:00</option>
<option value="">---------</option>
<option value="17">Anyday drop-in 12:30</option>
</select>
or:
<select name="session" class="form-control" title="" required id="id_session">
<option value="" selected>---------</option>
<option value="">No scheduled sessions for Monday</option>
<option value="">---------</option>
<option value="17">Anyday drop-in 12:30</option>
</select>
A solution I am using for some of these lists is to insert the breaks into the database, and let the sorting put them in the right places:
Table "classes":
id name sort
5 ----- -1
8 French 0
22 German 1
396 Italian 3
1 ----- 20
66 Maths 21
60 Physics 22
600 Chemistry 23
etc
This method has its own issues: it only really works for relatively “fixed” lists (so doesn’t work for the “Sessions” table) and the user can select the “-----” breaks - so they could potentially get past the form checking entering an invalid selection (or at least one we don’t want them to choose).
With the Session
queryset I know that I can join two querysets, but I can’t work out how to put an “empty(ish)” instance between them:
bigqueryset = monday_set | empty_instance | any_set
And how to get the “blanks/spacers” not to have id
in the select -> option
so that they are not valid in the form?
I thought that probably the easiest way to solve the Session
issue was to concatenate two or three lists together, but form.fields['fieldname'].queryset
actually wants a queryset, rather than something iterable.
Sorry if I am asking too many questions at once! Thanks in advance.