【问题标题】:Django: Displaying fields from intermediary tables in formsDjango:在表单中显示来自中间表的字段
【发布时间】:2016-02-24 12:11:46
【问题描述】:

这方面的大多数问题似乎都集中在节省 m2m 表上。我很好奇如何以一种(或两种组合)形式查看中间表中的字段。

我的想法是我有很多资源和很多饭菜。不同的膳食可以具有相同的资源,但数量不同。说:墨西哥卷饼有 x 磅牛肉,但墨西哥卷饼有 y。

我想创建一个表单来编辑墨西哥卷饼餐,以便我可以查看/编辑/创建:餐点名称、餐点中的资源以及与该餐点中的资源关联的数量。我当前的代码通过 m2m 表显示了一个表单,其中除了与资源相关的金额之外的所有金额

我有两个模型通过中间表连接:

class Resource(models.Model):
    name = models.CharField(max_length=200)
    unit = models.ForeignKey(Unit)
    units_per_pack = models.PositiveSmallIntegerField()
    packs_per_case = models.PositiveSmallIntegerField()
    allergens = models.ManyToManyField(Allergen, blank=True)

class Meal(models.Model):
    name = models.CharField(max_length=200)
    resources=models.ManyToManyField(Resource,through='MealResourceRelationship')
    recipe = models.TextField(default='')

class MealResourceRelationship(models.Model):
    resource = models.ForeignKey(Resource)
    meal = models.ForeignKey(Meal)
    units_per_person = models.DecimalField(max_digits=19,decimal_places=2)

我正在尝试使用如下所示的简单 ModelForm:

class MealForm(forms.ModelForm):
    class Meta:
    model = Meal
    fields = '__all__'

用这种观点:

def meal_edit(request, pk=None, template_name='foodstuffs/meal_edit.html'):
    if id:
        meal = get_object_or_404(Meal, pk=pk)
    else:
        meal = Meal()
    if request.POST:
       form = MealForm(request.POST,instance=meal)
       if form.is_valid():
            meal_mod = form.save(commit=False)
            meal_mod.save()

            # remove existing resources                                                                                                                                                                      
            meal_mod.resources.clear()
            for resource in form.cleaned_data.get('resources'):
                meal_resource_rel = MealResourceRelationship(meal=meal_mod,
                                                             resource=resource,
                                                             units_per_person=1)
                meal_resource_rel.save()
            # messages.add_message(request, messages.SUCCESS, _('Meal correctly saved.'))                                                                                                                    
            # If the save was successful, redirect to another page                                                                                                                                           
            redirect_url = reverse('meal_list')
            return HttpResponseRedirect(redirect_url)
    else:
        form = MealForm(instance=meal)

    args = {}
    args.update(csrf(request))
    args['form'] = form
    args['meal'] = meal
    return render_to_response(template_name, args)

有什么想法吗?谢谢!

【问题讨论】:

    标签: python django django-forms m2m


    【解决方案1】:

    基于 Django 提供的解决方案(缺少完全自定义的表单),我认为最容易分两部分看待这个问题:

    1. 如何为与给定膳食相关的所有 MealResourceRelationships 提供表单
    2. 如何将数字 1 中的表格与膳食本身的表格一起显示

    第 1 点的答案在于 Formsets,它允许一起呈现表单的多个实例。对于您希望将这些实例绑定到父对象(一顿饭)的特定情况,您对Inline Formsets 感兴趣,它允许您呈现由外键关联的表单的多个实例。 请参阅此post,了解如何通过关系使用带 m2m 的内联表单集。

    对于第 2 部分),您只需要将原始表单和内联表单集呈现到同一页面。有关示例,请参阅此 post

    基于此,您可以按如下方式更新您的视图:

    def meal_edit(request, pk=None, template_name='foodstuffs/meal_edit.html'):
        # ADDED: Created an inline formset factory for the meal resource relationship
        MealResourceFormset = forms.inlineformset_factory(Meal, Meal.resources.through, exclude=[])
    
        if id:
            meal = get_object_or_404(Meal, pk=pk)
        else:
            meal = Meal()
    
        if request.POST:
           form = MealForm(request.POST, instance=meal)
           if form.is_valid():
                meal_mod = form.save(commit=False)
                meal_mod.save()
    
                # remove existing resources                                                              
                meal_mod.resources.clear()
                for resource in form.cleaned_data.get('resources'):
                    meal_resource_rel = MealResourceRelationship(meal=meal_mod,
                                                             resource=resource,
                                                             units_per_person=1)
                    meal_resource_rel.save()
                # messages.add_message(request, messages.SUCCESS, _('Meal correctly saved.'))            
                # If the save was successful, redirect to another page                                   
                redirect_url = reverse('meal_list')
                return HttpResponseRedirect(redirect_url)
        else:
            # ADDED/EDITED: create both the meal form and resource formsets
            meal_form = MealForm(instance=meal)
            resource_formset = MealResourceFormset(instance=meal)                                                         
    
        args = {}
        args.update(csrf(request))
        args['form'] = meal_form
        # ADDED: pass through resource_formset to template
        args['formset'] = resource_formset
        args['meal'] = meal
        return render_to_response(template_name, args)
    

    您还需要更新模板以呈现表单集,并更新 MealForm 以不呈现资源字段(因为您是通过表单集呈现它)。您可以通过编辑每个部分的表单来进一步自定义每个部分。

    希望这对您的项目有所帮助,祝您好运!

    【讨论】:

      猜你喜欢
      • 2011-11-08
      • 2011-02-22
      • 2011-10-11
      • 2021-11-10
      • 2017-07-29
      • 2020-10-24
      • 1970-01-01
      • 2014-05-27
      相关资源
      最近更新 更多