使用新的“虚拟”保存基于类的视图表单集项目。柱 [英] Saving class-based view formset items with a new "virtual" column

查看:56
本文介绍了使用新的“虚拟”保存基于类的视图表单集项目。柱的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在表单内有一个由表单集生成的表格。

I have a table inside a form, generated by a formset.

在这种情况下,我的问题是在修改了其中一项之后,保存了所有项目,添加新的虚拟列作为其他两列的总和(仅在显示表格时生成,而不保存)。
我尝试了不同的方法,但是没有人在工作。

In this case, my problem is to save all the items after one of them is modified, adding a new "virtual" column as the sum of other two (that is only generated when displaying the table, not saved). I tried different ways, but no one is working.

问题


  • 保存根本不起作用。当它只是一种形式,但不适用于该形式集时,它就起作用了。

  • 我试图将列 amount 生成为<$ c box_one box_two 的$ c> Sum 均未成功。我也尝试过以这种方式生成表单,但这不起作用:

  • This save is not working at all. It worked when it was only one form, but not for the formset
  • I tried to generate the column amount as a Sum of box_one and box_two without success. I tried generating the form this way too, but this is not working:

formset = modelformset_factory(
    Item, form=ItemForm)(queryset=Item.objects.order_by(
        'code__name').annotate(amount=Sum('box_one') + Sum('box_two')))


此问题与上一个有关,但这个新方法更简单:
Pre-使用Django从数据库填充HTML表单表

This issue is related to this previous one, but this new one is simpler: Pre-populate HTML form table from database using Django

StackOverflow上的先前相关问题非常老,对我不起作用。

Previous related issues at StackOverflow are very old and not working for me.

我正在使用Django 2.0.2

I'm using Django 2.0.2

任何帮助将不胜感激。

Any help would be appreciated. Thanks in advance.

当前代码:

models.py

class Code(models.Model):
    name = models.CharField(max_length=6)
    description = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Item(models.Model):
    code = models.ForeignKey(Code, on_delete=models.DO_NOTHING)
    box_one = models.IntegerField(default=0)
    box_two = models.IntegerField(default=0)

    class Meta:
        ordering = ["code"]

views.py

class ItemForm(ModelForm):
    description = CharField()

    class Meta:
        model = Item
        fields = ['code', 'box_one', 'box_two']

    def save(self, commit=True):
        item = super(ItemForm, self).save(commit=commit)
        item.box_one = self.cleaned_data['box_one']
        item.box_two = self.cleaned_data['box_two']
        item.code.save()

    def get_initial_for_field(self, field, field_name):
        if field_name == 'description' and hasattr(self.instance, 'code'):
            return self.instance.code.description
        else:
            return super(ItemForm, self).get_initial_for_field(
                field, field_name)


class ItemListView(ListView):
    model = Item

    def get_context_data(self, **kwargs):
        data = super(ItemListView, self).get_context_data()
        formset = modelformset_factory(Item, form=ItemForm)()
        data['formset'] = formset
        return data

urls.py

app_name = 'inventory'
urlpatterns = [
    path('', views.ItemListView.as_view(), name='index'),

item_list.html

...
          <div>
            <form action="" method="post"></form>
            <table>
                {% csrf_token %}
                {{ formset.management_form }}
                {% for form in formset %}
                    <thead>
                        <tr>
                        {% if forloop.first %}
                            <th>{{ form.code.label_tag }}  </th>
                            <th>{{ form.description.label_tag }}  </th>
                            <th> <label>Amount:</label> </th>
                            <th>{{ form.box_one.label_tag }}  </th>
                            <th>{{ form.box_two.label_tag }}  </th>
                        {% endif %}
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>{{ form.code }}</td>
                            <td>{{ form.description }}</td>
                            <td>{{ form.amount }}</td>
                            <td>{{ form.box_one }}</td>
                            <td>{{ form.box_two }}</td>
                        </tr>
                    </tbody>

                {% endfor %}

                <input type="submit" value="Update" />
            </table>
            </form>
          </div>
...


推荐答案

使用虚拟注释查询列



总和集合表达式,在这种情况下,这不是您想要注释此查询的方式。相反,您应该使用 F表达添加两个数字字段的值

Annotating query with virtual column

Sum is an aggregate expression and is not how you want to be annotating this query in this case. Instead, you should use an F exrepssion to add the value of two numeric fields

qs.annotate(virtual_col=F('field_one') + F('field_two'))

因此校正后的查询集将为

So your corrected queryset would be

Item.objects.order_by('code__name').annotate(amount=F('box_one') + F('box_two'))

如果打算仅将该属性用于行级操作,则cezar提供的答案非常有用。但是,如果要基于金额进行查询,则需要对查询进行注释。

The answer provided by cezar works great if intend to use the property only for 'row-level' operations. However, if you intend to make a query based on amount, you need to annotate the query.

您尚未在视图类中提供 post 方法。您需要自己提供一个,因为您不是从可以为您提供视图的通用视图继承而来。请参见使用基于类的视图处理表单。您还应该考虑从处理表单的通用视图继承。例如, ListView 不实现 post 方法,但是实现 FormView

You have not provided a post method in your view class. You'll need to provide one yourself since you're not inheriting from a generic view that provides one for you. See the docs on Handling forms with class-based views. You should also consider inheriting from a generic view that handles forms. For example ListView does not implement a post method, but FormView does.

请注意,您的模板也不会呈现表单错误。由于您是手动呈现表单集,因此应考虑添加字段错误(例如 {{form.field.errors}} ),因此验证问题将在HTML。请参见手动呈现字段上的文档。

Note that your template is also not rendering form errors. Since you're rendering the formset manually, you should consider adding the field errors (e.g. {{ form.field.errors}}) so problems with validation will be presented in the HTML. See the docs on rendering fields manually.

此外,您可以在 post 方法中记录/打印错误。例如:

Additionally, you can log/print the errors in your post method. For example:

def post(self, request, *args, **kwargs):
    formset = MyFormSet(request.POST)
    if formset.is_valid():
        formset.save()
        return SomeResponse
    else:
        print(formset.errors)
        return super().post(request, *args, **kwargs)

然后,如果表单无法验证,您应该在控制台/日志中看到错误。

Then if the form does not validate you should see the errors in your console/logs.

这篇关于使用新的“虚拟”保存基于类的视图表单集项目。柱的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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