Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change multiple select field to multiple input fields for a many-to-many case?

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',)
like image 360
adeleinr Avatar asked Nov 05 '22 09:11

adeleinr


1 Answers

Sexiest Solution

You could use one of the jquery autocommplete tools described here: 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.

like image 171
Jordan Reiter Avatar answered Nov 09 '22 08:11

Jordan Reiter