使用 Django 从数据库预填充 HTML 表单表

Posted

技术标签:

【中文标题】使用 Django 从数据库预填充 HTML 表单表【英文标题】:Pre-populate HTML form table from database using Django 【发布时间】:2018-08-15 22:08:32 【问题描述】:

我有一个基于类的视图(views.py 中的IndexView),它显示了一个表,其中包含存储在数据库中的所有数据。 此视图在 index.html 中呈现,使用 def get_queryset(self) 获取所有数据。还没有问题。

对我来说困难的部分是尝试使用表单来修改和保存 amount 列。 我对 POST 部分没有任何问题,我使用 AJAX 保存新值。 我遇到的问题是从数据库中获取初始值以填充 Django 表单 (forms.py)

我尝试在表单字段的定义中使用initial 参数(在forms.py),甚至在表单定义中覆盖__init__但我不知道如何获得“一个价值”。我的意思是,我在测试中越接近使用以下内容填充 MultipleChoiceFieldforms.ModelMultipleChoiceField(queryset=Item.objects.order_by('code__name')) (实现Item object (1), Item object (2), etc.的多选字段)

但是如何使用数据库的内容填充单个 IntegerFieldCharField 以在模板中显示基于表单的表格字段?

我首先尝试使用单个项目(尝试了解如何引用一个项目/值以使用数据库填充它们),然后再使用整个表:

index.hml:

...
  <form class='my-ajax-form' method='POST' action='.' data-url=' request.build_absolute_uri|safe '>
    % csrf_token %
    form.as_table|safe
    <button type='submit'>Save changes</button>
  </form>
...

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)
    amount = models.IntegerField(default=0)

forms.py:

class ItemForm(forms.Form):
    code = forms.CharField(max_length=6)
    description = forms.CharField(max_length=100)
    amount = forms.IntegerField()

views.py:

class IndexView(generic.ListView, AjaxFormMixin, FormView):
    template_name = 'inventory/index.html'
    context_object_name = 'items_list'
    form_class = ItemForm

    def form_invalid(self, form):
        ...

    def form_valid(self, form):
        ...

    def get_queryset(self):
        ...

我检查了这些文档和一些类似的旧问题,但我尝试了一些建议/示例但没有成功:

https://docs.djangoproject.com/en/2.0/topics/forms/modelforms/#a-full-example https://www.webforefront.com/django/formprocessing.html Pre-populating Django Forms Populate a django form with data from database in view

我正在使用 Django 2.0.2

任何帮助将不胜感激。 提前致谢。


编辑: 尝试按照 andi 的建议使用 UpdateView 做某事。添加(尝试通过 id 获取一个值):

class ItemUpdate(UpdateView):
    form_class = JoinForm

    def get_object(self,queryset=None):
        obj = Item.objects.get(id=self.kwargs['2'])
        return obj

并将网址指向path('', views.ItemUpdate.as_view(), name='index'),但总是得到KeyError: '2'

【问题讨论】:

我不确定在您的情况下使用 django 表单是否准确。对于类似的需求,我使用 jquery editinplace (github.com/siebertm/jquery-edit-in-place):它简单高效。 【参考方案1】:

直接在模型上使用通用from django.views.generic.edit import UpdateView 怎么样?

https://docs.djangoproject.com/en/2.0/ref/class-based-views/generic-editing/#updateview

views.py:

from django.forms import ModelForm, CharField, Textarea
from django.urls import reverse_lazy
from django.views.generic import UpdateView

from demo.models import Item


class ItemForm(ModelForm):
    description = CharField(widget=Textarea)

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

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

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


class ItemUpdateView(UpdateView):

    form_class = ItemForm
    model = Item

    def get_success_url(self):
        return reverse_lazy('item-detail', kwargs='pk': 1)

urls.py

from django.conf.urls import url
from django.contrib import admin
from django.urls import path


from demo.views import ItemUpdateView

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    path(r'items/<int:pk>/', ItemUpdateView.as_view(), name='item-detail')
]

/templates/demo/item_form.html

<form action="" method="post">% csrf_token %
     form.as_p 
    <input type="submit" value="Update" />
</form>

如果有关设置或配置的内容不清楚,请参阅带有演示的 repo:https://github.com/andilabs/cbv

更新

添加了在 ListView 中生成所需内容的模型表单集

from django.forms import modelformset_factory


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

这只是以表格的形式显示数据,你有休息的地方。

【讨论】:

嗨!但那是为了用自己的 URL 或类似的东西创建一个“编辑按钮”,不是吗?我不知道如何使用 UpdateView 来填充初始表单。昨天我在读这个:simpleisbetterthancomplex.com/series/2017/10/09/… 试一试。从教程中复制示例代码,看看它是如何工作的。该视图的表单将在旅途中自动生成。 我尝试使用 UpdateView 进行操作,但我认为我的操作方式不正确...(在帖子末尾添加)(参考:chriskief.com/2015/01/19/…)跨度> 在调用formset.save() 时,实际上会为每个表单实例调用方法 save(),所有表单都已完成迭代并执行 save()。见github.com/django/django/blob/master/django/forms/… 我不知道在哪里使用 formset.save >. 【参考方案2】:

据我所知,有多种方法可以将数据加载到表单中:

在views.py中

您正在使用 FormView CBV,它有一个名为 get_intial 的函数:

    def get_initial(self):
        initial = super().get_initial()
        initial['<form-field>'] = <initial-value>
        return initial
在 forms.py 中

您可以覆盖 init 函数:

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['<form-field>'].initial = <initial-value>

【讨论】:

【参考方案3】:

可以做的一件事是遍历item列表,将每个字段的input标签的value属性设置为form.field_name.value

【讨论】:

以上是关于使用 Django 从数据库预填充 HTML 表单表的主要内容,如果未能解决你的问题,请参考以下文章

预填充 Django(非模型)表单

Django:ModelForm 使用自定义查询预填充复选框

基于 Web 请求预填充 Django 表单

需要澄清使用 Django 1.4 表单向导,特别是预填充和保存

如何使用链接从数据库中预填充表单字段?

如何根据先前的用户选择在 Django 中预填充(多个)ChoiceField