views:

100

answers:

1

I have a model Calendar and in a form I want to be able to create multiple instances of it.

Here are my models:

class Event(models.Model):
    user = models.ForeignKey(User)

class Group(models.Model):
    name = models.CharField(_('Name'), max_length=80)
    events = models.ManyToManyField(Event, through='Calendar')

class Calendar(models.Model):
    event = models.ForeignKey(Event)
    group = models.ForeignKey(Group)

class CalendarInline(admin.TabularInline):
    model = Calendar
    extra = 1

class GroupAdmin(admin.ModelAdmin):
    inlines = (CalendarInline,)

Here is how I try to code my form:

class AddEventToGroupForm(ModelForm):
    group = ModelMultipleChoiceField(queryset=Group.objects.all(), widget=SelectMultiple())

    def save(self):
        for g in self:
            g.save()

    class Meta:
        model = Calendar
        fields = ('group',)

And here is a part of my view:

e = Event.objects.get(id=event_id)
calentry = Calendar(event=e)
if request.POST:
    f = AddEventToGroupForm(data=request.POST, instance=calentry)
    if f.is_valid():
        f.save()

If I try to submit that form, I get:

AttributeError at /groups/add_event/7/

'BoundField' object has no attribute 'save'

What is the proper way to create multiple instances of Calendar in this situation?

+2  A: 

That's not how to deal with many-to-many relationships in forms. You can't iterate through fields in a form and save them, it really doesn't work that way.

In this form, there's only one field, which happens to have multiple values. The thing to do here is to iterate through the values of this field, which you'll find in the cleaned_data dictionary (when the form is valid).

So, in your view, you do something like:

if f.is_valid():
    for group in f.cleaned_data['group']:
        calentry.groups.add(group)

Note you're not 'saving' the AddEventToGroupForm form at all. I would make it a standard forms.Form, rather than a ModelForm, as you're not really depending on any of the ModelForm functionality.

Daniel Roseman