简体   繁体   中英

Django ModelForm passing multiple ManytoMany that are using through?

I am trying to figure out how to get two things figured out with Django (1.6) forms. I am looking to create a form using ModelForm with a model that has more then one ManyToManyField using through. I can seem to figure out how to get the ManyToMany items to be displayed in the form.

The one other thing I am trying to figure out is how to split up the form. For example if I wanted a form that looked like this.

Note: How its part of the Recipe Model (name, desciption) then the ManyToManyField (Fruit and items that go with it.) then another item from the Recipe Model (Fruit_notes) and then the second ManyToManyField...etc

Form Example:

Name: __________________ Description: ___________


Fruit: ___________ QTY: _________
Fruit Notes: ____________


Veg: ___________ qty: __________
veg notes:___________


models.py File

               from django.db import models


    class Vegetable(models.Model):
        name = models.CharField(max_length=150, blank=True)
        description = models.TextField(blank=True)

        def __unicode__(self):
            return self.name


    class Fruit(models.Model):
        name = models.CharField(max_length=150, blank=True)
        description = models.TextField(blank=True)

        def __unicode__(self):
            return self.name




    class Recipe(models.Model):
        name = models.CharField(max_length=450, blank=True)
        description = models.TextField(blank=True)
        fruits = models.ManyToManyField('Fruit', through='RecipeFruit')
        fruit_notes = models.TextField(blank=True)
        vegetables = models.ManyToManyField('Vegetable' through='RecipeVegetable')
        Vegetables_notes = models.TextField()


    class RecipeVegetable(models.Model):
        recipe = models.ForeignKey(Recipe)
        veg = models.ForeignKey(Vegetable)
        qty = models.FloatField()  


    class RecipeFruit(models.Model):
        recipe = models.ForeignKey(Recipe)
        fruit = models.ForeignKey(Fruit)
        qty = models.FloatField()

forms.py File

    from django import forms
    from django.forms import ModelForm, Textarea
    from django.forms.formsets import formset_factory
    from models import Recipe, Vegetable, Fruit
    from crispy_forms.helper import FormHelper
    from crispy_forms.layout import Submit

    class CreateRecipeForm(forms.ModelForm):

        class Meta:
            model = Recipe


        def __init__(self, *args, **kwargs):
            super(CreateRecipeForm, self).__init__(*args, **kwargs)
            self.helper = FormHelper()
            self.helper.form_id = 'id-RecipeForm'
            self.helper.form_class = 'form-inline'
            self.helper.form_method = 'post'
            self.helper.form_action = 'submit_survey'

            self.helper.add_input(Submit('submit', 'Submit'))

I did come across this question. What are the steps to make a ModelForm work with a ManyToMany relationship with an intermediary model in Django?

Looks like a great step toward figuring this out but I am having a hard time grasping on how to bring in two items. (In example, fruit and Vegetable)

If someone could point my in the right direction on this and provide a little example, it would be so greatly appreciated. When looking at the django docs, I don't really see anything that spells this out.

I was working the other day with a one to many relation, and settled to this solution (I modified a bit the names from my source to yours just for understanding). I haven't tested YOUR example, but it should work with small modifications (if needed), remember that formsets work only on ForeignKeys, If the bellow does not work, try also model = Recipe.fruits.through or Recipe.vegetables.through. The bellow is for only one inline formset, but you could add additional formsets with the same way:

    # forms.py

class RecipeForm(forms.ModelForm):
    ...
    class Meta:
        model = Recipe
        ....

class FruitForm(forms.ModelForm):
    ...
    class Meta:
        model = RecipeFruit
    ...


RecipeFormSet = inlineformset_factory(Recipe, RecipeFruit, form=FruitForm, extra=1)


# views.py

class RecipeCreateView(CreateView):
    form_class = RecipeForm
    template_name = "recipes/recipe_add.html"
    success_url = reverse_lazy('recipe-lists')

    def get(self, request, *args, **kwargs):
        """
        Handles GET requests and instantiates blank versions of the form
        and its inline formsets.
        """
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        recipe_formset = RecipeFormSet()
        return self.render_to_response(
            self.get_context_data(form=form,recipe_formset=recipe_formset))

    def post(self, request, *args, **kwargs):
        """
        Handles POST requests, instantiating a form instance and its inline
        formsets with the passed POST variables and then checking them for
        validity.
        """
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        recipe_formset = RecipeFormSet(request.POST)
        if (form.is_valid() and recipe_formset.is_valid()):
            return self.form_valid(form, recipe_formset)
        else:
            return self.form_invalid(form, recipe_formset)

    def form_valid(self, form, recipe_formset):
        """
        Called if all forms are valid. Creates a Recipe instance along with
        associated Ingredients and Instructions and then redirects to a
        success page.
        """
        self.object = form.save()
        recipe_formset.instance = self.object
        recipe_formset.save()
        return super(RecipeCreateView, self).form_valid(form)

    def form_invalid(self, form, recipe_formset):
        """
        Called if a form is invalid. Re-renders the context data with the
        data-filled forms and errors.
        """
        return self.render_to_response(
            self.get_context_data(form=form,recipe_formset=recipe_formset))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM