Ok - so one more day of working through this did the trick and I got through all of my issues and am successfully using modelformset, both when creating new objects and when editing existing ones. I thought I'd recap here in case anyone is searching for formset info, and also to give any developers that are reading this some examples of new and different usage issues.
First, in order to create a formset for a bunch of objects that don't yet exist (ie, the form is the user's way of creating the objects) I am setting initial inside _construct_form(), as Malcolm suggested: def _construct_form(self, i, **kwargs): kwargs["tile"] = self.tiles[i] kwargs["initial"] = {'tile':self.tiles[i].id} return super(TaskDetailCustomBaseFormSetForCreate, self)._construct_form(i, **kwargs) I think that this is the best way to create initial data with a modelformset. I was never successful using the initial argument when constructng the formset from the formset factory class and I think that would probably require a lot more hacking get it to work. Once you use the initial argument, ie like this: TaskTileDetailFormSet = modelformset_factory(TaskTileDetail, form=TaskTileDetailForm, formset=TaskTileDetailCustomBaseFormSetForCreate) taskTileDetailFormSet = TaskTileDetailFormSet(data=data, tiles=tileList, initial= [{"tile":tile.id} for tile in tileList]) it seems that the modelformset code thinks you have 'n' existing objects, and you get errors like this: -> kwargs['instance'] = self.get_queryset()[i] (Pdb) n IndexError: 'list index out of range' So for anyone using modelformsets - put your initial data into construct_form(). One thing that I spent some time thinking about was whether I could identify which form was which by indexing into my formset during the POST. I think Malcolm's suggestion was that I create the formset for the GET, and then create the same formset for the POST (but with postdict data this time). I think the point was that since I am creating the data myself during the POST, I should know what's what and shouldn't be able to just index in at the right point. After thinking about this for some time, I think there is a problem with this approach, at least for my app. Let's say my app displays a form that presents the users with book titles for a set of books, and the user is filling out the author and submitting the form. Now, suppose the app also allows a user to change the books in the group (ie, via some other url). I think this would make it impossible to use the indexing method because the formset that I create during POST might not be the same as the formset I create during the GET. IE, I'd run into this case if one user goes to the form where they fill out authors and then sits on that form for awhile, and meanwhile some other user goes and changes the books in the group. For error checking purposes, I think I need to send the book titles as hidden inputs with the form, that when I proceses the POST, if some of those titles are now gone, I can identify which titles are still valid and also generate good error messags for the ones that are not. This example is sort of contrived, but in the system I'm designing, it could happen and I'd like to be able to cover it gracefully. The code I created to check for this error is pretty ugly, in that it reaches right into the django source private space. This assumes that fieldName is some "hidden" field that lets me identify each form. The code below compares the post data to the initial data, in a similar to manner to the get_changed_data() function in the source. Here it is: def getFormContinuityError(form, fieldName): """Confirm that the 'initial' value for fieldName is the same as the 'data' value for fieldName. This protects from case where the fieldNames have changed between the get and post. """ data_value = form.fields[fieldName].widget.value_from_datadict (form.data, form.files, form.add_prefix(fieldName)) initial_value = form.initial.get(fieldName, form.fields [fieldName].initial) has_changed = form.fields[fieldName].widget._has_changed (initial_value, data_value) return has_changed def getFormSetContinuityError(formSet, fieldName): continuityError = 0 for form in formSet.forms: if getFormContinuityError(form, fieldName): continuityError = 1 break return continuityError I will probably no doubt regret this code some day when I update to a new version of django! A second thing that I needed to do that is perhaps different from what other people have needed was to save the formset forms even if they are empty. In my particular app, the user is creating tasks. They put in a description of the task and each task has 1 or more results, one per "tile". Associated with each tile is an optional set of "special instructions", and a location for the tile owner to input their result. When creating the task, I create the formset to give the user a way to identify which tiles are associated with the task. When the user creates the task, they need to choose which tiles it is for, but they may not have any special tile instructions and they definitely don't have the result. So I had a situation where I did need to be able to save empty forms. IE, once the user submits the task, I want a tile object to exist for each tile they selected. I found that when my formset forms were empty, the existing framework gave me no cleaned data and in fact would not let me save the form to an object. I got around this by simply creating a dummy field, which I set to a value in the view.py POST code. After setting that dummy field in the postdict, I created the formset and having that dummy field caused has_changed() to be true, which allowed the cleaned_data to be created and allowed the form.save() to actually do a save. Anyway, that's it. It's been a long haul (took me about 3 days to really grock what is going on) but it's cool now that it is working. Malcolm, thanks for all your help. I don't think I could have gotten it working without your pointers and high level review. Margie --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~----------~----~----~----~------~----~------~--~---