我已经整理了一份表格来保存食谱。 它使用表单和内联表单集。 我的用户拥有包含食谱的文本文件,他们希望剪切和粘贴数据以使输入更容易。 我已经弄清楚如何在处理原始文本输入后填充表单部分,但我不知道如何填充内联表单集。
似乎解决方案几乎已经在这里阐明:http://code.djangoproject.com/ticket/12213但我无法完全将各个部分放在一起。
我的模特:
#models.py
from django.db import models
class Ingredient(models.Model):
title = models.CharField(max_length=100, unique=True)
class Meta:
ordering = ['title']
def __unicode__(self):
return self.title
def get_absolute_url(self):
return self.id
class Recipe(models.Model):
title = models.CharField(max_length=255)
description = models.TextField(blank=True)
directions = models.TextField()
class Meta:
ordering = ['title']
def __unicode__(self):
return self.id
def get_absolute_url(self):
return "/recipes/%s/" % self.id
class UnitOfMeasure(models.Model):
title = models.CharField(max_length=10, unique=True)
class Meta:
ordering = ['title']
def __unicode__(self):
return self.title
def get_absolute_url(self):
return self.id
class RecipeIngredient(models.Model):
quantity = models.DecimalField(max_digits=5, decimal_places=3)
unit_of_measure = models.ForeignKey(UnitOfMeasure)
ingredient = models.ForeignKey(Ingredient)
recipe = models.ForeignKey(Recipe)
def __unicode__(self):
return self.id
配方表单是使用 ModelForm 创建的:
class AddRecipeForm(ModelForm):
class Meta:
model = Recipe
extra = 0
视图中的相关代码(解析表单输入的调用被删除):
def raw_text(request):
if request.method == 'POST':
...
form_data = {'title': title,
'description': description,
'directions': directions,
}
form = AddRecipeForm(form_data)
#the count variable represents the number of RecipeIngredients
FormSet = inlineformset_factory(Recipe, RecipeIngredient,
extra=count, can_delete=False)
formset = FormSet()
return render_to_response('recipes/form_recipe.html', {
'form': form,
'formset': formset,
})
else:
pass
return render_to_response('recipes/form_raw_text.html', {})
如上所述,当 FormSet() 为空时,我可以成功启动该页面。 我尝试了几种方法来向表单集提供我已确定的数量、测量单位和成分,包括:
任何建议都非常感谢。
我的第一个建议是采取简单的方法:保存
Recipe
和 RecipeIngredient
,然后在制作 Recipe
时使用生成的 FormSet
作为实例。您可能想在您的配方中添加一个“已审核”布尔字段,以指示表单集随后是否已被用户批准。
但是,如果您出于某种原因不想走这条路,您应该能够像这样填充表单集:
我们假设您已将文本数据解析为食谱成分,并且有一个像这样的字典列表:
recipe_ingredients = [
{
'ingredient': 2,
'quantity': 7,
'unit': 1
},
{
'ingredient': 3,
'quantity': 5,
'unit': 2
},
]
“成分”和“单位”字段中的数字是相应成分和计量单位对象的主键值。我假设您已经制定了某种将文本与数据库中的成分相匹配的方法,或者创建新的方法。
然后你可以这样做:
RecipeFormset = inlineformset_factory(
Recipe,
RecipeIngredient,
extra=len(recipe_ingredients),
can_delete=False)
formset = RecipeFormset()
for subform, data in zip(formset.forms, recipe_ingredients):
subform.initial = data
return render_to_response('recipes/form_recipe.html', {
'form': form,
'formset': formset,
})
这会将表单集中每个表单的
initial
属性设置为 recipe_ingredients
列表中的字典。它似乎在显示表单集方面对我有用,但我还没有尝试保存。
我无法让 Aram Dulyan 代码适用于此
for subform, data in zip(formset.forms, recipe_ingredients):
subform.initial = data
显然 django 1.8 上发生了一些变化,我无法迭代cached_property
forms - django.utils.function.cached_property 对象位于 0x7efda9ef9080
我收到此错误
zip 参数 #1 必须支持迭代
但是我仍然使用字典并将其直接分配给我的表单集并且它有效,我从这里获取了示例:
https://docs.djangoproject.com/en/dev/topics/forms/formsets/#understanding-the-managementform
从 django.forms 导入 formset_factory 从 myapp.forms 导入 ArticleForm
ArticleFormSet = formset_factory(ArticleForm, can_order=True)
formset = ArticleFormSet(initial=[
{'title': 'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
{'title': 'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
])
我的将表单集分配给模板的代码
return self.render_to_response(
self.get_context_data(form=form, inputvalue_numeric_formset=my_formset(initial=formset_dict)
我可以毫无困难地将
initial
传递给内联表单集——而不是工厂方法,最重要的是——大约 Django 4.1,FWIW。
MyInlineFormSet = inlineformset_factory(ParentModel, ChildModel, ...)
formset = MyInlineFormSet(initial=[{...}])
距最初的问题已经过去 12 年多了,所以代码库很可能已经改变,和/或者我可能误读了这里的一些答案和评论,但希望这个澄清可能对那些正在寻找如何解决问题的人有所帮助做吧。
我必须处理几乎类似的情况来显示每个仓库的库存。 实际可用库存应以考虑到已编程但尚未由其他员工验证的库存之间的账户转账的形式进行更新。
首先,我将这些传输记录在传递给表单的查询集中:
already_transferts = Transfert.objects.filter(
product=product, processed=False).select_related('emetteur')
stock_to_fill = count_total_warehouses - count_current_product_warehouses
stock_inline_formset = inlineformset_factory(Produit, SstStock,
form=SstStockForm,
extra=stock_to_fill,
can_delete=False,
)
[...]
s_form = stock_inline_formset(
instance=product, form_kwargs={'empty_sst': empty_sst,
'user_is_staff':user.is_staff,'already_transferts':already_transferts})
然后,以
__init__
的形式,我像这样更新 qty
:
class SstStockForm(forms.ModelForm):
class Meta:
model = SstStock
fields = ('qty', 'warehouse', 'maxsst', 'adresse', 'pua', 'cau')
def __init__(self, *args, **kwargs):
self.empty_sst = kwargs.pop('empty_sst', None)
self.user_is_staff = kwargs.pop('user_is_staff', None)
# programmed transferts must be removed from availability
self.already_transferts = kwargs.pop('already_transferts', None)
super().__init__(*args, **kwargs)
# if transfers are already programed for this product, remove their availability
if self.already_transferts:
for a in self.already_transferts:
init = self.initial
if init['warehouse'] == a.emetteur_id:
init['qty'] = init['qty'] - a.qty
不确定这是最好/更干净的方法,但这效果很好。