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
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.