views:

40

answers:

2

When I display the ToolBoxEditForm it uses a multiple select field. But what I want is a form that lets the user edit each tool he has in the toolbox as a text field. I cant figure out how to do this with the many-to-many field.

class Tool(models.Model):
    tool_name = models.CharField(unique=True, max_length=200)
......

class ToolBox(models.Model):
    tools = models.ManyToManyField(Tool,max_length=300)

class ToolBoxEditForm (ModelForm):
    tools = ???
    class Meta:
      model = ToolBox
      exclude  = ('user', 'popularity',)
A: 

I'm not sure, since not tested it, but here is the logic goes.

  1. Create formset for ToolBoxEditForm via formset_factory
  2. Change tool_name field type to CharField
  3. Set number of rows in formset to precisely the number of Tool objects available in db
  4. Pass in initials to formset constructor to fill in tool_name textboxes.

    # TODO: following data must be generated dynamically

    initial_data=[{'tool_name': u'first_tool_name', }, {'tool_name': u'second_tool_name',}]

    formset = ToolBoxFormSet(extra=0, initial=initial_data)

Not sure about the validation part. Here we are placing tool_name as value for textbox. During validation, Form may expect ID (because it is supposed to be listbox). But, you can handle that also.

for more info about formset refer: http://docs.djangoproject.com/en/dev/topics/forms/formsets/

Narendra Kamma
+1  A: 

Sexiest Solution

You could use one of the jquery autocommplete tools described here: http://stackoverflow.com/questions/1191807/facebook-style-jquery-autocomplete-plugin

Then in the form:

class ToolBoxEditForm (ModelForm):
    tools = forms.CharField(widget=forms.Textarea, required=False)

    def clean_tools(self):
        tool_data = self.cleaned_data.get('tools',None)
        tools = []
        #here, a comma is used a delim, so it's not allowed in the tool name.
        for td in tool_data.split(','): 
            t, _ = Tool.objects.get_or_create(name=td)
            tools.append(t)
        return tools

    class Meta:
      model = ToolBox
      exclude  = ('user', 'popularity',)

You'd have to figure out how to modify the JavaScript so that new items could be entered (i.e. not just ones already in the database).

Alternative Solution

This is sort of what the inline formsets were created for, so Narendra's solution will work.

Something like:

from django.forms.models import inlineformset_factory

def manage_toolbox(request, toolbox_id):
    toolbox = Toolbox.objects.get(pk=toolbox_id)
    ToolInlineFormSet = inlineformset_factory(Toolbox, Tool)
    if request.method == "POST":
        formset = ToolInlineFormSet(request.POST, request.FILES, instance=toolbox)
        if formset.is_valid():
            formset.save()
            # Do something.
    else:
        formset = ToolInlineFormSet(instance=toolbox)
    return render_to_response("manage_toolbox.html", {
        "formset": formset,
    })

Not that this form is only for editing the items within the toolbox. If you want the user to be able to edit other aspects of the Toolbox -- say, its name or description -- you would create a separate form and output both of them inside the same <form></form> tags.

Jordan Reiter
This is exactly what I ended up doing!! I used the jquery approach. It works beautifully. Thanks!
adeleinr