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

Django中如何保存BaseInlineFormSet代码初始化数据并实现权重分配?

Django内联表单集保存全月份权重值解决方案

一、调整表单集基础配置

确保表单集强制生成对应月份数量的表单,避免仅处理用户修改过的实例:

from django.forms import inlineformset_factory

# 绑定主模型Variable与子模型MonthAllocat,固定生成对应月份数的表单
VariableMonthAllocationInlineFormSet = inlineformset_factory(
    Variable,
    MonthAllocat,
    form=MonthAllocationForm,
    formset=FieldTargetSumFormSetMixin,
    extra=0,  # 不生成额外空白表单
    min_num=len(MONTH_CHOICES),  # 强制生成与月份数匹配的表单数量
    validate_min=True,
    can_delete=False  # 禁止删除月份表单
)

二、重写表单集save方法,处理权重分配与全实例保存

在表单集的save方法中,先收集用户修改的权重数据,计算剩余权重并按比例分配给未修改月份,再强制标记所有表单为已修改状态,确保全部实例被保存;同时通过self.instance直接获取关联的Variable实例ID:

class VariableMonthAllocationInlineFormSet(FieldTargetSumFormSetMixin, BaseInlineFormSet):
    def save(self, commit=True):
        # 收集用户已修改的月份权重
        modified_weights = {}
        for form in self.forms:
            if form.cleaned_data:
                month = form.cleaned_data["month"]
                modified_weights[month] = form.cleaned_data["weight"]

        # 计算剩余权重及未修改月份的分配比例
        total_modified = sum(modified_weights.values())
        remaining_weight = Decimal("100.00") - total_modified
        unmodified_months = [f.instance.month for f in self.forms if f.instance.month not in modified_weights]
        per_month_weight = remaining_weight / len(unmodified_months) if unmodified_months else Decimal("0.00")

        # 给未修改表单填充权重并标记为已修改,确保被保存
        for form in self.forms:
            month = form.instance.month
            if month not in modified_weights:
                form.cleaned_data["weight"] = per_month_weight
                form.changed_data.append("weight")

        # 调用父类方法保存所有实例
        instances = super().save(commit=commit)

        # 兜底处理新创建Variable时的漏存情况
        if commit:
            variable = self.instance
            for month_num, _ in MONTH_CHOICES:
                if not MonthAllocat.objects.filter(variable=variable, month=month_num).exists():
                    # 无修改时用平均权重,有修改时用分配后的权重
                    weight = modified_weights.get(month_num, per_month_weight) if modified_weights else Decimal("100.00")/len(MONTH_CHOICES)
                    MonthAllocat.objects.create(variable=variable, month=month_num, weight=weight)
        return instances

三、优化表单初始化逻辑,绑定默认月份与权重

修改MonthAllocationForm的初始化方法,给新表单绑定默认月份和平均权重,确保表单实例能关联到对应月份:

class MonthAllocationForm(forms.ModelForm):
    class Meta:
        model = MonthAllocat
        fields = ["month", "weight"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 给新创建的表单设置默认月份和平均权重
        if not self.instance.pk:
            initial_month = kwargs.get("initial", {}).get("month")
            if initial_month:
                self.instance.month = initial_month
                self.initial["month"] = initial_month
                avg_weight = Decimal("100.00") / len(MONTH_CHOICES)
                self.initial["weight"] = avg_weight
                self.instance.weight = avg_weight

四、调整Admin内联配置,传递初始月份数据

在Admin内联的get_formset方法中,给新创建的Variable实例预先生成所有月份的表单初始数据:

class MonthAllocationInline(admin.TabularInline):
    model = MonthAllocat
    form = MonthAllocationForm
    formset = VariableMonthAllocationInlineFormSet
    extra = 0

    def get_formset(self, request, obj=None, **kwargs):
        formset = super().get_formset(request, obj, **kwargs)
        # 新创建Variable时,生成所有月份的初始表单数据
        if obj is None:
            avg_weight = Decimal("100.00") / len(MONTH_CHOICES)
            formset.initial = [
                {"month": num, "weight": avg_weight} for num, _ in MONTH_CHOICES
            ]
        return formset

内容的提问来源于stack exchange,提问作者Brenon 28

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 07:44:58