如何在 Inlineformset 中动态过滤 ModelChoice 的查询集?

Posted

技术标签:

【中文标题】如何在 Inlineformset 中动态过滤 ModelChoice 的查询集?【英文标题】:How to dynamically filter ModelChoice's queryset in a Inlineformset? 【发布时间】:2018-04-14 22:40:28 【问题描述】:

我只想过滤内联表单集中的选择字段。

场景:

每个任务都有自己的报告。每个任务都有一个预订。预订有几个预订项目。我想根据报告表单中的预订仅显示相关的bookeditems。使用signals 生成报告表单并在编辑时我' m 使用inlineformsetinstances 填充表单。

这是我的代码:

模型.py

class Task(models.Model):

    booking = models.ForeignKey(
        Booking, blank=False, null=True, related_name='booking_id',)
    ......


class Report(models.Model):

    task = models.ForeignKey(
        Task, blank=True, null=True, related_name='task',)

    hoarding = models.OneToOneField(
        BookedItem, blank=True, null=True, related_name='+')

    status = models.CharField(
        max_length=32, choices=ReportStatus.CHOICES, blank=True, null=True, default=ReportStatus.INCOMPLETE)

views.py

def report(request, pk):
    task_instance = get_object_or_404(Task, pk=pk)
    booking = task_instance.booking_id
    #all bookeditems here
    bookeditems = BookedItem.objects.filter(Booking_id=bookeditem)

     # inline formsetfactory
    ReportFormset = inlineformset_factory(Task,Report,form=TaskReportForm,fields=('hoarding','status',), extra=0,can_delete=False,)
    data = request.POST or None
    formset = ReportFormset(instance=task_instance)
    for form in formset:
                form.fields['hoarding'].queryset = bookeditems.all()

    if request.method == 'POST':
        formset = ReportFormset(request.POST,instance=task_instance)
        if formset.is_valid():
            formset.save
            return redirect('taskreport')
        else:
             formset = ReportFormset(instance=task_instance)    
    else:
        formset = ReportFormset(instance=task_instance)
    return render(request, 'report.html', 'formset': formset,
                                                       'bookeditems': bookeditems,
                                                       'task_instance': task_instance)

forms.py

class TaskReportForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(TaskReportForm, self).__init__(*args, **kwargs)
    class Meta:
        model = PrinterReport
        fields = ['hoarding','status',]
        exclude = ['printer_task',]

report.html:

<form action="." method="POST">% csrf_token %
       formset.management_form 

           <section id="account" class="nice-padding active">
                              <div class="link-formset">
                                <table class="listing listing-page">
                                          <thead>
                                            % for form in formset %
                                                % if forloop.first %
                                                    % for field in form %
                                                        <th> field.label_tag </th>
                                                    % endfor %
                                                % endif %
                                          </thead>
                                          <tbody>
                                                <tr>
                                                    % for field in form %
                                                        <td> field </td>
                                                    % endfor %
                                                </tr>
                                            % endfor %
                                          </tbody>
                                      </table>
                              </div>            

                  </section>

                   <li class="">
                        <input type="submit" value="Save" class="button">
                    </li>

                            </ul>
                        </fieldset>
</form>

我想在每个报告囤积字段中仅将相关的预定项目显示为选择字段。

我试过上面的代码,但没有结果。

【问题讨论】:

【参考方案1】:

您使用名称 formset 定义您的表单集,并在此处正确自定义您的字段的查询集:

for form in formset:
    form.fields['hoarding'].queryset = bookeditems.all()

但是您稍后会在您的视图中覆盖 formset 变量,从而消除该初始逻辑的影响:

if request.method == 'POST':
        formset = ReportFormset(request.POST,instance=task_instance)
        if formset.is_valid():
            formset.save
            return redirect('taskreport')
        else:
             #invaild form, re-render with errors - and no custom querysets
             formset = ReportFormset(instance=task_instance)    
    else:
        #non-POST request, render form - again overwriting custom querysets
        formset = ReportFormset(instance=task_instance)

【讨论】:

那么,我哪里做错了?我应该做些什么改变?

以上是关于如何在 Inlineformset 中动态过滤 ModelChoice 的查询集?的主要内容,如果未能解决你的问题,请参考以下文章

Django - 修改Inlineformset删除按钮

Django - 修改 Inlineformset 删除按钮

在 Django 表单集中过滤对象

django:如何在表单向导中使用 inlineformset?

具有一个模型和 inlineformset 的 Formwizard

在 Django 的 inlineformset_factory 中选择外键元素的子集