Django - UpdateView与内联表单试图保存重复的记录? [英] Django - UpdateView with inline formsets trying to save duplicate records?

查看:244
本文介绍了Django - UpdateView与内联表单试图保存重复的记录?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个费用模型和一个 ExpenseLineItem 模型。就像典型的费用/发票一样,一个费用可以有几个订单项来弥补发票的总成本。我正在尝试使用基于类的视图来创建和更新费用。我已经成功地编写了 CreateView ,以创建一个包含多个费用订单项的新费用。

I have an Expense model and an ExpenseLineItem model. Just like a typical expense/invoice, one expense can have several line items to make up the total cost of an invoice. I'm trying to use class based views to create and update expenses. I've successfully coded the CreateView to make a new expense with multiple expense line items.

我的问题是当我尝试更新已经有多个费用订单项的现有费用。下面是我的代码,我无法弄清楚问题是什么。 mixins( TitleMixin CancelSuccessMixin SelectedApartment )是我的并且工作正常。

My problem is when I try and update an existing Expense which already has several expense line items. Here's my code below, and I can't figure out what the issue is. The mixins (TitleMixin, CancelSuccessMixin, SelectedApartment)are mine and work fine.

我发现一个错误,我相信这意味着它试图保存的新的副本ExpenseLineItems 但失败,因为那些已经存在。几乎就像我没有提供实例参数。

I'm getting an error that, I believe, means that it's trying to save a new copy of the ExpenseLineItems but fails since those already exist. Almost like I'm not providing an instance argument.

我做错了什么?

forms.py

class ExpenseForm(ModelForm):
  class Meta:
    model = Expense
    fields = ['apart', 'inv_num', 'vendor', 'due_date']

ExpenseLineItemFormset = inlineformset_factory(Expense, ExpenseLineItem, fields=('description', 'account', 'amt'), can_delete=False)

这是我的 ExpenseUpdate 视图:

class ExpenseUpdate(TitleMixin, CancelSuccessMixin, SelectedApartment, UpdateView):
  model = Expense
  form_class = ExpenseForm
  template_name = 'accounting/expense.html'

  def get(self, request, *args, **kwargs):
    self.object = self.get_object()
    form_class = self.get_form_class()
    form = self.get_form(form_class)
    expense_line_item_form = ExpenseLineItemFormset(instance = self.object)
    return self.render_to_response(self.get_context_data(form = form, expense_line_item_form = expense_line_item_form))

  def post(self, request, *args, **kwargs):
    self.object = self.get_object()
    form_class = self.get_form_class()
    form = self.get_form(form_class)
    expense_line_item_form = ExpenseLineItemFormset(self.request.POST, instance=self.object)

    if (form.is_valid() and expense_line_item_form.is_valid()):
      return self.form_valid(form, expense_line_item_form)
    return self.form_invalid(form, expense_line_item_form)

  def form_valid(self, form, expense_line_item_form):
    self.object = form.save()
    expense_line_item_form.instance = self.object
    expense_line_item_form.save()
    return HttpResponseRedirect(self.get_success_url())

  def form_invalid(self, form, expense_line_item_form):
    return self.render_to_response(self.get_context_data(form=form, expense_line_item_form=expense_line_item_form))

错误代码我得到:

MultiValueDictKeyError at /stuff/2/accounting/update-expense/25/
"u'expenselineitem_set-0-id'"
Request Method: POST
Request URL:    http://localhost:8000/stuff/2/accounting/update-expense/25/
Django Version: 1.8.3
Exception Type: MultiValueDictKeyError
Exception Value:    
"u'expenselineitem_set-0-id'"
Exception Location: /usr/local/lib/python2.7/dist-packages/django/utils/datastructures.py in __getitem__, line 322

修改:我的模板的相关部分:

Edit: Relevant part of my template:

<form class="form-horizontal" action="" method="post">
  {% csrf_token %}
  {% load widget_tweaks %}
 <div class="row">
    <div class="col-md-12">
      <table class="table table-tight">
        <thead>
          <th>Description</th>
          <th class="text-right">Account</th>
          <th class="text-right">Amount</th>
        </thead>
        <tbody>
          {{ expense_line_item_form.management_form }}
          {% for eli in expense_line_item_form %}
          <tr>
            <td>{{ eli.description|attr:'cols:29' }}</td>
            <td class="text-right">{{ eli.account }}</td>
            <td class="text-right">{{ eli.amt }}</td>
          </tr>
          {% endfor %}
        </tbody>
      </table>
    </div>
  <div class="col-md-12 text-right">
    <a href="{{ cancel }}" class="btn btn-default btn-lg">Cancel</a>
    <input class="btn btn-success btn-lg" type="submit" value="Post" />
  </div>
  <br><br>
</form>

编辑 - 工作表单模板我以为我会添加工作版本如果有人需要它:

EDIT -- Working Form Template I thought I would add the working version of my template, should someone else need it:

    <tbody>
      {{ expense_line_item_form.management_form }}
      {% for eli in expense_line_item_form %}
      <tr>
        <td>{{ eli.id }} {{ eli.description|attr:'cols:29' }}</td> <!-- <<==== Here's where I simply added {{ eli.id }}. That's all I changed :) -->
        <td class="text-right">{{ eli.account }}</td>
        <td class="text-right">{{ eli.amt }}</td>
      </tr>
      {% endfor %}
    </tbody>


推荐答案

您需要将每个表单的表单id formset(它不会显示给用户,因为它被渲染为隐藏的输入)。没有这种形式,POST数据中缺少值,你会看到一个 KeyError

You need to include the form id for each form in the formset (it won't be shown to the user, as it is rendered as a hidden input). Without that form, the value is missing from the POST data, and you get a KeyError as you are seeing.

formset docs


注意我们需要如何显式呈现 {{form.id}} 。这样可以确保在POST情况下的模型表单将能正常工作。 (这个例子假设一个主键叫做id,如果你已经明确定义了自己的主键,这个主键不被称为id,请确保它被渲染。)

Notice how we need to explicitly render {{ form.id }}. This ensures that the model formset, in the POST case, will work correctly. (This example assumes a primary key named id. If you’ve explicitly defined your own primary key that isn’t called id, make sure it gets rendered.)

在您的情况下,您正在循环使用 {%for eli in expense_line_item_form%} ,因此您需要包含 {{eli.id}}

In your case, you are looping through the formset with {% for eli in expense_line_item_form %}, so you need to include {{ eli.id }}.

这篇关于Django - UpdateView与内联表单试图保存重复的记录?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆