使用 Django 从数据库中预填充 HTML 表单 table
Pre-populate HTML form table from database using Django
我有一个基于 class 的视图(IndexView 位于 views.py)显示 table 将所有数据存储在数据库中。
此视图在 index.html 中呈现,使用 def get_queryset(self)
获取所有数据。还没有问题。
对我来说困难的部分是尝试使用表单来修改和保存 amount 列。
POST 部分没有问题,我在其中使用 AJAX 来保存新值。
我遇到问题的地方是从数据库中获取初始值以填充 Django 表单 (forms.py)
我尝试在表单字段的定义中使用 initial
参数(在 forms.py),甚至在表单中覆盖 __init__
定义,但我不知道如何得到"one value"。我的意思是,我在测试中越接近填充 MultipleChoiceField :
forms.ModelMultipleChoiceField(queryset=Item.objects.order_by('code__name'))
(实现选择题Item object (1), Item object (2), etc.
)
但是如何使用数据库的内容填充单个 IntegerField 或 CharField 以显示基于表单的 table 模板中的字段?
我首先尝试使用单个项目(尝试了解如何引用一个 item/value 以使用数据库填充它们),然后再使用整个 table:
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):
...
我检查了这些文档和一些类似的旧问题,但我尝试了一些 suggestions/examples 但没有成功:
- 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
如有任何帮助,我们将不胜感激。
提前致谢。
编辑:
尝试按照我的建议使用 UpdateView 做一些事情。添加(尝试通过id获取一个值):
class ItemUpdate(UpdateView):
form_class = JoinForm
def get_object(self,queryset=None):
obj = Item.objects.get(id=self.kwargs['2'])
return obj
并将 url 指向 path('', views.ItemUpdate.as_view(), name='index')
但总是得到 KeyError: '2'
直接在模型上使用通用 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>
如果有关设置或配置的内容不清楚,请参考带有演示的回购协议:https://github.com/andilabs/cbv
更新
添加了 modelformset 生成您在 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
这只是在表单中显示数据,您需要休息。
据我所知,有多种方法可以将数据加载到表单中:
- 在views.py
您正在使用 FormView
CBV,它有一个名为 get_intial
:
的函数
def get_initial(self):
initial = super().get_initial()
initial['<form-field>'] = <initial-value>
return initial
- 在forms.py
您可以覆盖 init func:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['<form-field>'].initial = <initial-value>
你可以做的一件事是遍历项目列表,并将每个字段的输入标签的值属性设置为form.field_name.value
我有一个基于 class 的视图(IndexView 位于 views.py)显示 table 将所有数据存储在数据库中。
此视图在 index.html 中呈现,使用 def get_queryset(self)
获取所有数据。还没有问题。
对我来说困难的部分是尝试使用表单来修改和保存 amount 列。 POST 部分没有问题,我在其中使用 AJAX 来保存新值。 我遇到问题的地方是从数据库中获取初始值以填充 Django 表单 (forms.py)
我尝试在表单字段的定义中使用 initial
参数(在 forms.py),甚至在表单中覆盖 __init__
定义,但我不知道如何得到"one value"。我的意思是,我在测试中越接近填充 MultipleChoiceField :
forms.ModelMultipleChoiceField(queryset=Item.objects.order_by('code__name'))
(实现选择题Item object (1), Item object (2), etc.
)
但是如何使用数据库的内容填充单个 IntegerField 或 CharField 以显示基于表单的 table 模板中的字段?
我首先尝试使用单个项目(尝试了解如何引用一个 item/value 以使用数据库填充它们),然后再使用整个 table:
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):
...
我检查了这些文档和一些类似的旧问题,但我尝试了一些 suggestions/examples 但没有成功:
- 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
如有任何帮助,我们将不胜感激。 提前致谢。
编辑: 尝试按照我的建议使用 UpdateView 做一些事情。添加(尝试通过id获取一个值):
class ItemUpdate(UpdateView):
form_class = JoinForm
def get_object(self,queryset=None):
obj = Item.objects.get(id=self.kwargs['2'])
return obj
并将 url 指向 path('', views.ItemUpdate.as_view(), name='index')
但总是得到 KeyError: '2'
直接在模型上使用通用 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>
如果有关设置或配置的内容不清楚,请参考带有演示的回购协议:https://github.com/andilabs/cbv
更新
添加了 modelformset 生成您在 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
这只是在表单中显示数据,您需要休息。
据我所知,有多种方法可以将数据加载到表单中:
- 在views.py
您正在使用 FormView
CBV,它有一个名为 get_intial
:
def get_initial(self):
initial = super().get_initial()
initial['<form-field>'] = <initial-value>
return initial
- 在forms.py
您可以覆盖 init func:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['<form-field>'].initial = <initial-value>
你可以做的一件事是遍历项目列表,并将每个字段的输入标签的值属性设置为form.field_name.value