Formset:保存模型不起作用

Formset: saving models won't work

一整天都在努力完成这项工作。我有一个主要模型,它是入门级的。一个条目可以包括多个班次。这是用于存储工作时间的应用程序的一部分。这是创建条目的视图:

class EntryCreateView(FormView):
    template_name = 'entry/create.html'
    form_class    = AddWorkDay
    success_url   = reverse_lazy('time_manager:index')

    def get(self, request, ordinal=None, *args, **kwargs):
        """ Initiates with a blank form or will populate the day field with the day represented by the passed
            ordinal. """
        if ordinal:
            day  = datetime.datetime.fromordinal(int(ordinal))
            form = AddWorkDay(initial={'day': day})
        else:
            form = AddWorkDay()
        formset = ShiftFormSet()

        return render(request, self.template_name, {'form': form, 'formset': formset})

    def post(self, request, ordinal=None, *args, **kwargs):
        form    = AddWorkDay(data=request.POST)
        formset = ShiftFormSet(data=request.POST)
        errors  = []
        shifts  = []

        if form.is_valid() and formset.is_valid():
            # Build entry.
            entry       = form.save(commit=False)
            entry.owner = request.user
            errors.extend(entry.validate(request.user))

            # Build shift.
            for form in formset:
                shift       = form.save(commit=False)
                shift.entry = entry
                shifts.append(shift)
                errors.extend(shift.validate(request.user))

            if len(errors) == 0:
                entry.save()
                for shift in shifts:
                    shift.save()
                return HttpResponseRedirect(reverse('time_manager:index'))

        return render(request, self.template_name, {'form': form, 'formset': formset, 'errors': errors, 'shifts': shifts, 'entry': entry})

当我尝试输入带有 shift 的条目并按保存时,它终止说: “/time_manager/entry/create/ 处的完整性错误 NOT NULL 约束失败:shift_shift.entry_id”。我试图弄清楚班次有什么问题,所以我评论了保存班次的块(从 "if len(errors)" 到 "return HttpResponseRedirect.")所以它会 return 到带有表单的视图。然后我将 {{ shifts }} 放入我的模板中,看看里面有什么。当我这样做时,它终止于:“NoReverseMatch at /time_manager/entry/create/ 反向 'edit' 与参数 '()' 和关键字参数 '{'pk': None}' 未找到。尝试了 1 种模式:['time_manager/entry/shift/edit/(?P(\d+))/$']" 就好像我在尝试使用引用不存在的视图的 {% url %} 标签。所以我猜有些事情发生了当我尝试保存formset的形式时出错。但是,我反复阅读django文档,这是存储formset形式的方式,不是吗?

好吧,我重新审视了我的代码,然后我想到了。我想确保首先正确构建条目和每个班次,然后仅在它们不违反任何规则时才保存它们。所以正如你在上面看到的:我用 commit=False 保存了两者。然而,这意味着该条目尚未分配主键。主键是我的班次模型上的 ForeignKeyField 所需要的。这就是 Django 保存失败的原因。
我稍微改变了方法的顺序。这是工作代码:

def post(self, request, ordinal=None, *args, **kwargs):
    form    = AddWorkDay(data=request.POST)
    formset = ShiftFormSet(data=request.POST)
    errors  = []
    shifts  = []

    if form.is_valid() and formset.is_valid():
        # Build entry.
        entry       = form.save(commit=False)
        entry.owner = request.user
        errors.extend(entry.validate(request.user))

        # Build shift.
        for form in formset:
            shift       = form.save(commit=False)
            shifts.append(shift)
            errors.extend(shift.validate(request.user))

        # If there are no errors, save the entry ans it's shifts.
        if len(errors) == 0:
            entry.save()
            for shift in shifts:
                shift.entry = entry
                shift.save()
            return HttpResponseRedirect(reverse('time_manager:index'))

    return render(request, self.template_name, {'form': form, 'formset': formset, 'errors': errors, 'shifts': shifts, 'entry': entry})

注意 entry 是如何被第二次保存的(没有 commit=False)然后分配给 shift。