views:

137

answers:

3

Hello guys,

I've looked at formset and model formset at Django many times, but I still can't figure the smart way to do this.

I have two models:

Group

Person

I have a queryset that contains all the persons trying to join a particular group: Person.objects.filter(wantsToJoinGroup=groupD)

Now, what I want to do, is display a page with a checkbox at the side of each person that wants to join a particular group. Those checkboxes can then be checked and then the button 'Accept to Group' is clicked. I want this to bulk add those persons to a certain group.

What I fail to understand how to do is exactly the checkbox thing. I've been trying to extend a modelform and then make a formset out of it, but I fail at it everytime. It seems like if I want to do a formset with models I should use modelformset, but that does not allow me to extend the form to add a checkbox. How can I do it?

Here is a 10-second draft on paint of what I would like to have:

alt text

So it's basically, a checkbox and a way to access the person model at the template and then a way to proccess this on the view.

Thanks in advance!

Edit: By the way, before someone suggests using ModelMultipleChoiceField, unless there is a way to access each of the objects inside it on the template, this will not fulfill what I need to do. As far as I know, I can't iterate over the objects of ModelMultipleChoiceField on the template. Please correct me if I'm wrong!

A: 

At the top of my head, you can insert a hidden field called 'Action'. On the onclick event of the Accept and Reject buttons, set the value of the hidden field appropriately and then submit the form.

In your view, check the value of the hidden field to figure out if it's Accept or Reject.

dannyroa
Hello Danny, thank you for answer... I was looking for something on the Django side, no javascript involved preferentiallyRegarding the checkboxes, how can they be done?
Clash
Not sure if that is possible without javascript because you cannot selectively submit form fields. If you don't want javascript, make Accept and Reject radio buttons and have a separate submit button.
dannyroa
+1  A: 

If you're not married to the idea of using a modelform, I would just use a regular form, with a ModelMultipleChoiceField, give it a queryset in the __init__ then provide that same queryset to the template context (to iterate over at your leisure):

#view
def add_to_group(request):
    persons = Person.objects.filter(wantsToJoinGroup=groupD)
    if request.POST:
        form = PersonAddForm(persons, request.POST)
        if form.is_valid():
            #your handling logic
    form = PersonAddForm(persons)
    context = {'persons': persons, 'form': form}
    return render_to_response(template, context)

#form
class PersonAddForm(forms.Form):
    def __init__(self, queryset, *args, **kwargs):
        super(PersonAddForm, self).__init__(*args, **kwargs)
        self.fields['persons'] = forms.ModelMultipleChoiceField(queryset=queryset,
                                     widget=forms.CheckboxSelectMultiple() )
DrBloodmoney
Hello! Thank you for your answer! I'm trying your solution, but my form is always returing false for is_valid(), any idea why?
Clash
Just figured I needed to pass request.POST and queryset arg to the form... by the way, needed to use `kwargs.pop('queryset', None)` to get it to work, thanks!
Clash
You shouldn't have to pop it, because you are passing it as a positional argument and not a keyword. I use this pattern a good bit. You'll have to pass the request.POST to the form to validate (on POST obviously), but not on get. I'll edit to be explicit.
DrBloodmoney
Ah, I see, so I send it as a non-keyworded arg! Thank you
Clash
+1  A: 

You can actually get to ModelMultipleChoiceField's items this way:

my_field.field.queryset

where my_field is an instance of ModelMultipleChoiceField.

Dmitry Shevchenko
Thank you for your answer!
Clash