Dear all,
I’m trying to manage a model form where one of the filed comes from a M2M relationship. I would like to know if what I intend to do can be done “naturally”, as a solution I imagine looks to me a bit “nasty”, with javascript and hidden field.
I have 2 models : Event
, on which the form is based, and UserGroup
, linked to Event
with M2M relationship. To create / update an event, I would like to have a list with as many groups as defined, and a checkbox in front of each group to allow the user to select groups he wants to be part of the event.
Here is the form as I defined it yet:
class EventDetail(forms.ModelForm):
groups = forms.ModelMultipleChoiceField(
label = "Liste des groupes",
queryset = None,
widget = forms.CheckboxSelectMultiple,
required = False
)
class Meta:
model = Event
fields = ['event_name', 'event_date', 'quorum', 'rule']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
instance = kwargs.get('instance', None)
self.fields['groups'].queryset= UserGroup.objects.\
filter(company=instance.company, hidden=False).\
order_by('group_name')
Then comes the first question: how to manage the display, and add information regarding each group? I mean, groups
have dedicated attributes, and I would like to be able to display some of them.
At this stage, the solution I implemented is to define an __str__()
method dedicated to this display.
But, while I was at the beginning focused on this first question, I was able to display check boxes, and even to manage users choices (when he (un)selected some choices, the POST updated database accordingly.
Unfortunately, I was convinced it was “natural”, and now that I decided to use this workaround, I’m not able anymore to display, even less manage check boxes.
Here is my view (please do not pay attention to formsets… this will probably be the subject of my next publication here ^^):
@user_passes_test(lambda u: u.is_superuser or (u.id is not None and u.usercomp.is_admin))
def adm_event_detail(request, comp_slug, evt_id=0):
company = Company.get_company(request.session['comp_slug'])
QuestionFormset = formset_factory(QuestionDetail, extra=3)
if evt_id > 0:
current_event = Event.objects.get(id=evt_id)
event_form = EventDetail(request.POST or None, instance=current_event)
question_set = QuestionFormset(initial=Question.objects.filter(event=current_event))
else:
event_form = EventDetail(request.POST or None)
question_set = QuestionFormset()
if request.method == 'POST':
if any(event_form.is_valid(), question_set.is_valid()):
if evt_id == 0:
# Create new event
event_data = {
"company": company,
"groups": event_form.cleaned_data["groups"],
"event_name": event_form.cleaned_data["event_name"],
"event_date": event_form.cleaned_data["event_date"],
"quorum": event_form.cleaned_data["quorum"],
"rule":event_form.cleaned_data["rule"]
}
new_event = Event.create_event(event_data)
else:
new_event = event_form.save()
for item in question_set:
if item.cleaned_data:
question = item.save()
new_event
else:
print("****** FORMULAIRE NON VALIDE *******")
print(event_form.errors)
return render(request, "polls/adm_event_detail.html", locals())
Finally, here is the part of the template where the form is supposed to be displayed:
<ul style="list-style-type: none">
{% for grp in event_form.groups %}
<li>{{ grp }}</li>
{% endfor %}
</ul>
What I’m looking for is:
- groups already defined as part of the event are checked
- when I submit the form, the list of groups linked to the event is updated according to user’s choice, and the display after validation presents the latest status. At this stage, I have only empty check boxes
Many thanks in advance
PS: I’m using Django 2.2 so far