python - Django 多对多字段和表单
问题描述
我正在编写我的第一个 Django 应用程序,我的models.py
文件中有两个类,成分和膳食。一种食物有很多成分,您应该能够设置膳食中每种成分的数量,所以这就是我的models.py
:
class Ingredient(models.Model):
name = models.CharField(max_length=200)
class Meal(models.Model):
name = models.CharField(max_length=200)
ingredients = models.ManyToManyField(Ingredient, through='Recipe_Ingredient')
class Recipe_Ingredient(models.Model):
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE)
quantity = models.FloatField()
UNITY_CHOICES = (
('g', 'Gram(s)'),
('kg', 'Kilogram(s)'),
('l', 'Liter(s)'),
('cl', 'Centiliter(s)'),
)
quantityUnit = models.CharField(
max_length=2,
choices=UNITY_CHOICES,
default='g',
)
Recipe_Ingrent 类是用于存储数量的 ManyToMany 关联表。
这里的问题是我不知道在这种情况下如何使用表单。我有一个模板meal_edit.html
,它在form.py
.
要添加成分,我的表格很简单,如下所示:
from .models import Ingredient
class IngridientForm(forms.ModelForm):
class Meta:
model = Ingredient
fields = ('name',)
那么,我应该如何制作一个表格来创建一个包含多种成分和每种成分数量的食谱?
解决方案
从本质上讲,每个成分都是您较大表单中的一个表单(尽管<form
您的模板中只有一个标签。例如:
模型.py:
class Ingredient(models.Model):
name = models.CharField(max_length=200)
class Meal(models.Model):
name = models.CharField(max_length=200)
class Recipe_Ingredient(models.Model):
meal = models.ForeignKey(Meal, on_delete=models.CASCADE)
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE) # Not sure what this is, but I'll leave that to you
ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE)
quantity = models.FloatField()
UNITY_CHOICES = (
('g', 'Gram(s)'),
('kg', 'Kilogram(s)'),
('l', 'Liter(s)'),
('cl', 'Centiliter(s)'),
)
quantityUnit = models.CharField(
max_length=2,
choices=UNITY_CHOICES,
default='g',
)
表格.py:
from django import forms
from your_app import models
class IngredientForm(forms.ModelForm):
class Meta:
model = models.Recipe_Ingredient
fields = ['ingredient', 'quantity', 'quantityUnit']
IngredientFormset = forms.inlineformset_factory(models.Meal, models.Recipe_Ingredient, form=IngredientForm, extra=2)
视图.py:
from your_app import forms, models
class YourMealModelView():
model = models.Meal
def get_context_data(self, *args, **kwargs):
context_data = super().get_context_data(**kwargs)
if self.request.method == 'POST':
context_data['ingredients_formset'] = forms.IngredientFormset(
self.request.POST,
instance=self.object, # as in your Meal object
prefix='ingredients'
)
else:
context_data['ingredients_formset'] = forms.IngredientFormset(
instance=self.object, prefix='ingredients'
)
def form_valid(self, form):
# You can manipulate the formsets here as well:
context_data = self.get_context_data()
ingredients_formset = context_data['ingredients_formset']
meal = form.save()
for i_form in ingredients_formset:
delete = i_form.cleaned_data.get('DELETE')
if delete:
i_form.instance.delete()
continue
# do stuff and save
ingredient_recipe = i_form.save(commit=False)
ingredient_recipe.meal = meal
ingredient_recipe.save()
模板:
<form id="meal_form">
{% for field in form.fields %}
{{ field.label }}
{{ field }}
{% endfor %}
<table>
<thead>
{{ ingredients_formset.management_form }}
<tr>
<th>Ingredient</th>
<th>Quantity</th>
<th>Units</th>
<th>Delete?</th>
</tr>
</thead>
<tbody>
{% for i_form in ingredients_formset.forms %}
<tr id="{{ i_form.prefix }}">
{{ i_form.id }}
<td>{{ i_form.ingredient }}</td>
<td>{{ i_form.quantity }}</td>
<td>{{ i_form.quantityUnit }}</td>
<td>{% if i_form.instance.pk %}{{i_form.DELETE %}{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</form>
当然,我遗漏了很多东西,比如使用 javascript 向表单集添加新项目,如何处理新餐点与编辑现有餐点,以及使用什么 Django View 等,但这给了你一个想法。
推荐阅读
- javascript - 加载图像完成JQUERY后无法删除类
- typescript - 在 Cordova Typescript 项目中使用 ionic 4 插件
- javascript - 我可以给其他按钮提供与 Slick Carousel 点相同的功能吗
- c++ - 分配时出现分段错误
- java - JPA:延迟加载的数据在未调用时也会被获取
- ag-grid-angular - 将“复制此行”上下文菜单添加到 agGrid
- python-3.x - 覆盖列时的 Pandas SettingWithCopyWarning
- python - 更新数组和内部数组中匹配的所有对象
- c++ - 程序忽略用户名,只允许我输入密码?
- django - 为什么 React/TypeScript/axios 会忽略我的 CSRF cookie?