如何从两个相关模型中显示formset?

时间:2016-02-28 14:19:22

标签: django django-models django-forms django-views

是否有一种简单的方法来显示包含两个相关模型的表单?请在models.py文件中考虑这些:

class InvoiceList(models.Model):
    invoice_number = models.IntegerField(default=0)
    recipient = models.CharField(max_length=100)

class InvoiceItem(models.Model):
    item_description = models.CharField(max_length=150)
    list = models.ForeignKey(InvoiceList)

基本上,每张发票都可以有一个或多个发票项目。

forms.py:

class InvoiceListForm(ModelForm):
    class Meta:
        model = InvoiceList
        fields = ['invoice_number', 'recipient']

class InvoiceItemForm(ModelForm):
    class Meta:
        model = InvoiceItem
        exclude = ('list',)
        fields = ['item_description']

我的问题出在views.py

def update_edit(request, invoice_id):
    a = get_object_or_404(InvoiceList, pk=invoice_id)
    form = InvoiceListForm(instance=a)
    formset = InvoiceItemForm(instance=a)
    return render(request, 'file.html', {'invoice_info': form, 'items': formset})

file.html

<h1>Something Something Invoice</h1>

<form action="." name="stock_details" method="post">
{% csrf_token %}

{{ invoice_info.as_p }}

{% for item in items %}
    {{ item.as_table }}<br>
{% endfor %}

</form>

以上并不完全有效。它显示invoice_info,但不显示项目。我确定这与实例调用错误的东西有关。有人可以帮忙吗?谢谢!

urls.py

from django.conf.urls import url
from . import views

urlpatterns = [
    #This view is the main page when loaded
    url(r'^$', views.index, name='index'),

    #This view is when viewing the details
    url(r'^invoice/(?P<invoice_id>[0-9]+)/$', views.detail, name='detail'),

    #This view is when doing some function
    url(r'^add_new_invoice/$', views.add_new, name='add_new'),

    #This view is to delete an invoice
    url(r'^delete/(?P<invoice_id>[0-9]+)/$', views.delete, name='delete'),

    #This view is to update an invoice
    url(r'^update/(?P<invoice_id>\d+)/(?P<item_id>\d+)/$', views.update_edit, name='update_edit'),
]

index.html(这是列出发票的地方)

{% if latest_invoice_list %}
    <h1>Invoices</h1><br>

    <table border=1>
        <tr>
            <td width=50 align="center">Invoice Number</td>
            <td width=200 align="center">Recipient</td>
            <td align="center">Update/Resend</td>           
            <td align="center">Delete</td>
        </tr>

    {% for invoice in latest_invoice_list %}
        <tr>
            <td align="center">{{ invoice.invoice_number }}</td>
            <td align="center"><a href="/invoice/{{ invoice.id }}/">{{ invoice.recipient }}</a></td>
            <td align="center"><form action="{% url 'update_edit' invoice.id invoice.item_id %}" name="update" method="post" valign="bottom">{% csrf_token %}<input type="submit" value="Update"></form></td>
            <td align="center"><form action="{% url 'delete' invoice.id %}" name="delete" method="post" valign="bottom">{% csrf_token %}<input type="submit" value="Delete"></form></td>
        </tr>
    {% endfor %}
    </table>
    <a href="{% url 'add_new' %}">Create a new invoice</a>
{% else %}
    <p>No stocks were added. <a href="{% url 'add_new' %}">Create a new invoice now!</a></p>
{% endif %}

2 个答案:

答案 0 :(得分:0)

我认为你应该{{ items.as_table }}而不是你做的for循环。

同时添加前缀,因为它们位于同一HTML表单上,这将使数据知道它属于哪种形式

有关前缀的更多信息,请访问:https://docs.djangoproject.com/en/1.9/ref/forms/api/#prefixes-for-forms

修改

您正在尝试为InvoiceListInvoiceListForm使用InvoiceItemForm模型的实例,这样做无效。

由于您正在编辑它们,因此最好在网址中包含item_id,然后从中获取InvoiceItem的实例

def update_edit(request, invoice_id, item_id):
    a = get_object_or_404(InvoiceList, pk=invoice_id)
    i = get_object_or_404(InvoiceItem, pk=item_id)
    form = InvoiceListForm(instance=a, prefix="list")
    formset = InvoiceItemForm(instance=i, prefix="item")
    return render(request, 'file.html', {'invoice_info': form, 'items': formset})

只需包含item_id,然后从中获取外键中的InvoiceList实例。

 def update_edit(request, item_id):
    i = get_object_or_404(InvoiceItem, pk=item_id)
    form = InvoiceListForm(instance=i.list, prefix="list")
    formset = InvoiceItemForm(instance=i, prefix="item")
    return render(request, 'file.html', {'invoice_info': form, 'items': formset})

答案 1 :(得分:0)

好的,所以我设法通过使用inlineformset_factory来解决它,但放在forms.py文件中。所以这是以防任何人都在寻找它:

forms.py

# Added this new line at the top
from django.forms.models import inlineformset_factory

# Placed this at the very bottom
InvoiceFormSet = inlineformset_factory(InvoiceList, InvoiceItem, fields=('item_description',), extra=0)

views.py

# Added this line at the top
from .forms import InvoiceFormSet

# Adjusted the def to this
def update_edit(request, invoice_id):

    # Confirm and acquire the stuff from the main model
    a = get_object_or_404(InvoiceList, pk=invoice_id)

    # Acquire the related model stuff under the main model & assign to "b"
    b = InvoiceFormSet(instance=a, prefix="item")

    # Acquire the stuff from the main model & assign to "form"
    form = InvoiceListForm(instance=a, prefix="list")

    return render(request, 'file.html', {'invoice_info': form, 'items': b})

file.html

<h1>Something Something Invoice</h1>

<form action="." name="stock_details" method="post">
{% csrf_token %}

{{ invoice_info.as_p }}

{% for item in items %}
    {{ item.as_table }}<br>
{% endfor %}

</form>

项目中的&#34;项目&#34;现在也工作,可以通过这种方式迭代内容。奇怪的是,有一个&#34;删除&#34;单独出现的复选框。