You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django:为InlineFormSet中的字段添加自定义查询集

如何在InvoiceDetail的Inline FormSet中设置自定义Product查询集

没问题,我来帮你搞定这个需求。根据你的模型结构,我分两种最常见的使用场景来给出具体解决方案:Django Admin后台中的Inline配置,以及自定义视图里的InlineFormSet配置。

场景1:在Django Admin中配置

如果你是在Admin后台创建/编辑发票时使用Inline,只需要自定义InvoiceDetailInline类,重写formfield_for_foreignkey方法就能轻松过滤Product的查询集。比如我假设你想只显示当前发票所属公司的产品(如果你的Invoices模型后续会关联Company字段,也可以换成其他过滤逻辑,比如只显示有库存的产品):

from django.contrib import admin
from .models import Invoices, InvoiceDetail, Products

class InvoiceDetailInline(admin.TabularInline):
    model = InvoiceDetail
    extra = 1  # 默认显示的空表单行数

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        # 只针对product字段修改查询集
        if db_field.name == "product":
            # 获取当前正在编辑的发票ID(新建时为空)
            invoice_id = request.resolver_match.kwargs.get('object_id')
            if invoice_id:
                invoice = Invoices.objects.get(id=invoice_id)
                # 这里替换成你的实际过滤逻辑,比如筛选该发票所属公司的产品
                kwargs["queryset"] = Products.objects.filter(company=invoice.company)
            else:
                # 新建发票时,可显示所有产品,或根据当前用户所属公司过滤
                kwargs["queryset"] = Products.objects.all()
        return super().formfield_for_foreignkey(db_field, request, **kwargs)

class InvoicesAdmin(admin.ModelAdmin):
    inlines = [InvoiceDetailInline]

admin.site.register(Invoices, InvoicesAdmin)
admin.site.register(Products)

场景2:在自定义视图中使用InlineFormSet

如果是在自己写的视图里处理发票创建/编辑,需要先自定义InvoiceDetailForm来修改product字段的查询集,再基于这个表单创建InlineFormSet:

步骤1:自定义关联表单

from django import forms
from .models import InvoiceDetail, Products

class InvoiceDetailForm(forms.ModelForm):
    class Meta:
        model = InvoiceDetail
        fields = ['product', 'quantity_sold']

    def __init__(self, *args, **kwargs):
        # 取出额外传入的过滤参数(比如公司ID)
        self.company_id = kwargs.pop('company_id', None)
        super().__init__(*args, **kwargs)
        # 根据参数过滤产品查询集
        if self.company_id:
            self.fields['product'].queryset = Products.objects.filter(company_id=self.company_id)
        else:
            self.fields['product'].queryset = Products.objects.all()

步骤2:在视图中传递参数并生成FormSet

from django.forms import inlineformset_factory
from django.shortcuts import render, redirect
from .models import Invoices, InvoiceDetail
from .forms import InvoiceDetailForm

def create_invoice(request):
    # 基于自定义表单生成InlineFormSet
    InvoiceDetailFormSet = inlineformset_factory(
        Invoices, InvoiceDetail,
        form=InvoiceDetailForm,
        extra=1
    )

    if request.method == 'POST':
        invoice_form = forms.ModelForm(request.POST, model=Invoices)
        formset = InvoiceDetailFormSet(request.POST, instance=invoice_form.instance)
        if invoice_form.is_valid() and formset.is_valid():
            invoice = invoice_form.save()
            formset.save()
            return redirect('invoice_list')
    else:
        # 示例:获取当前用户所属公司ID作为过滤条件
        company_id = request.user.company.id
        invoice_form = forms.ModelForm(model=Invoices)
        # 给FormSet里的每个表单传入过滤参数
        formset = InvoiceDetailFormSet(instance=invoice_form.instance, form_kwargs={'company_id': company_id})

    return render(request, 'create_invoice.html', {
        'invoice_form': invoice_form,
        'formset': formset
    })

关键注意点

  • 过滤逻辑完全可以根据你的实际需求调整,比如换成Products.objects.filter(in_stock__gt=0)只显示有库存的产品,或者Products.objects.filter(is_active=True)只显示上架产品。
  • 如果是新建发票时还没确定关联公司,你可以先让用户选择公司,再通过AJAX动态加载对应产品列表(上面的方案是后端静态过滤的实现,适合不需要动态变化的场景)。

内容的提问来源于stack exchange,提问作者Hossam Salah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:12:40