[英]One form for two models in django
Django==3.1.7
django-crispy-forms==1.11.2
我有 2 個模型:Order 和 OrderList
Order 是 header,OrderList 是相關 Order 的表格部分
class Order(models.Model):
print_number = models.PositiveIntegerField(
verbose_name=_("Number"),
default=get_todays_free_print_number,
)
# ... some other fields
class OrderList(models.Model):
order = models.ForeignKey(
Order,
blank=False,
null=False,
on_delete=models.CASCADE
)
item = models.ForeignKey(
Item,
verbose_name=_("item"),
blank=True,
null=True,
on_delete=models.CASCADE
)
# ... some other OrderList fields
問題是如何創建一個包含兩個模型的表單,並提供將 Order 中的 OrderList 位置添加到表單中並保存它們的能力。
我做了什么:
forms.py - 我為 OrderList 使用了內聯表單集工廠
from django.forms import ModelForm
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
from .models import Order, OrderList
class OrderForm(ModelForm):
class Meta:
model = Order
fields = [
'__all__',
]
class OrderListForm(ModelForm):
class Meta:
model = OrderList
fields = [
'__all__',
]
class OrderListFormSetHelper(FormHelper):
"""Use class to display the formset as a table"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.template = 'bootstrap4/table_inline_formset.html'
# I am not sure we should add a button here
####################################################
self.add_input(Submit('submit', 'Submit',
css_class='btn btn-primary offset4'))
視圖.py
@login_required
def orders(request):
template = f'{APP_NAME}/index.html'
list_helper = OrderListFormSetHelper()
list_formset = inlineformset_factory(Order,
OrderList,
OrderListForm,)
if request.method == 'POST':
form = OrderForm(request.POST, prefix="header")
if form.is_valid() and list_formset.is_valid():
order = form.save()
order_list = list_formset.save(commit=False)
order_list.order = order
order_list.save()
return HttpResponseRedirect(reverse('order_created'))
else: # all other methods means we should create a blank form
form = OrderForm()
return render(request, template, {'form': form,
'list_form': list_formset,
'list_helper': list_helper})
索引.html
<form method="post">
{% csrf_token %}
{% crispy form %}
{% crispy list_form list_helper %}
<!-- the button below doesn't make sense because it does nothing.
the self.add_input in forms.py already adds a submit button.
-->
<button type="submit" class="btn btn-primary">
{% translate "Send an order" %}
</button>
</form>
您使用crispy
模板標簽來呈現您的 forms。 它使用FormHelper
class 來幫助呈現您的 forms,默認情況下,它的屬性form_tag
設置為True
,這使它為您呈現form
標簽。 這意味着您正在嵌套表單標簽,這在 HTML5 標准中不起作用並且是不可能的。 您需要將此屬性設置為False
以防止出現這種情況:
class OrderForm(ModelForm):
class Meta:
model = Order
fields = [
'__all__',
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper(self) # Explicitly set helper to prevent automatic creation
self.helper.form_tag = False # Don't render form tag
self.helper.disable_csrf = True # Don't render CSRF token
接下來,在您在視圖中創建的助手中,您還必須設置這些屬性。 此外,您稱為list_formset
的不是表單集的instance
,而是class ,因此您實際上需要實例化表單集 class 並使用它:
@login_required
def orders(request):
template = f'{APP_NAME}/index.html'
list_helper = OrderListFormSetHelper()
list_helper.form_tag = False # Don't render form tag
list_helper.disable_csrf = True # Don't render CSRF token
OrderListFormSet = inlineformset_factory(Order,
OrderList,
OrderListForm,)
if request.method == 'POST':
form = OrderForm(request.POST, prefix="header")
list_formset = OrderListFormSet(request.POST, instance=form.instance) # Instantiate formset
if form.is_valid() and list_formset.is_valid():
order = form.save()
order_list = list_formset.save()
# Remove below two line, have already instantiated formset with `form.instance` and called save without `commit=False`
# order_list.order = order
# order_list.save()
return HttpResponseRedirect(reverse('order_created'))
else: # all other methods means we should create a blank form
form = OrderForm()
list_formset = OrderListFormSet(instance=form.instance) # Instantiate formset
return render(request, template, {'form': form,
'list_form': list_formset,
'list_helper': list_helper})
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.