使用内联表单集创建模型和相关模型

che*_*art 42 django modelform inline-formset

[我已经在Django用户发布了这个| Google网上论坛也是.]

使用内联formset文档中的示例,我能够编辑属于特定模型的对象(使用模型形式).我一直在尝试使用相同的模式来 创建使用内联表单集的新对象,但是无法清除我的脑袋以便为此目的带出一个工作视图.

使用与上述链接相同的示例,我将如何创建"作者"模型的新实例及其相关的"书籍"对象?

pri*_*stc 38

首先,创建一个Author模型表单.

author_form = AuthorModelForm()
Run Code Online (Sandbox Code Playgroud)

然后创建一个虚拟作者对象:

author = Author()
Run Code Online (Sandbox Code Playgroud)

然后使用虚拟作者创建内联formset,如下所示:

formset = BookFormSet(instance=author)  #since author is empty, this formset will just be empty forms
Run Code Online (Sandbox Code Playgroud)

将其发送到模板.将数据返回到视图后,您将创建作者:

author = AuthorModelForm(request.POST)
created_author = author.save()  # in practice make sure it's valid first
Run Code Online (Sandbox Code Playgroud)

现在将内联formset与新创建的作者挂钩,然后保存:

formset = BookFormSet(request.POST, instance=created_author)
formset.save()   #again, make sure it's valid first
Run Code Online (Sandbox Code Playgroud)

编辑:

要在新表单上没有复选框,请执行以下操作:

{% for form in formset.forms %}
    <table>
    {% for field in form %}
        <tr><th>{{field.label_tag}}</th><td>{{field}}{{field.errors}}</td></tr>
    {% endfor %}

    {% if form.pk %} {# empty forms do not have a pk #}
         <tr><th>Delete?</th><td>{{field.DELETE}}</td></tr>
    {% endif %}
    </table>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)

  • 为了澄清,如果您按照文档的示例,您将使用BookFormSet = inlineformset_factory(Author,Book,can_delete = False)而不是BookFormSet = inlineformset_factory(作者,书籍),然后您将不需要执行{%if form.pk%}检查上面的nbv4的答案. (6认同)
  • 我没想到!! inlineformset_factory接受can_delete(当然!)所以我刚刚传递了can_delete = False. (2认同)
  • 这个答案的问题是即使BookFormset无效也可能保存作者,可能导致创建重复的作者.下面有两个答案可以解决这个问题. (2认同)

Mik*_*and 37

我实际上想对nbv4的解决方案提出一个小调整:

假设您没有在if-else语句之外创建空的created_author,因此需要将formset嵌套在author_form.is_valid()中,以避免在author_form无效时(因此没有实例化created_author)时出现运行时错误.

代替:

if request.method == 'POST':
    author_form = AuthorModelForm(request.POST)
    if author_form.is_valid():
        created_author = author_form.save()
        formset = BookFormSet(request.POST, instance=created_author)
        if formset.is_valid():
            formset.save()
            return HttpResponseRedirect(...)
else:
    ...
Run Code Online (Sandbox Code Playgroud)

请执行下列操作:

if request.method == 'POST':
    author_form = AuthorModelForm(request.POST)
    if author_form.is_valid():
        created_author = author_form.save(commit=False)
        formset = BookFormSet(request.POST, instance=created_author)
        if formset.is_valid():
            created_author.save()
            formset.save()
            return HttpResponseRedirect(...)
else:
    ...
Run Code Online (Sandbox Code Playgroud)

此版本避免在book_formset有机会验证之前提交created_author.用于纠正的用例是有人用无效的BookFormSet填写有效的AuthorForm并继续重新提交,创建多个没有与之关联的书籍的作者记录.这似乎适用于我的项目跟踪器应用程序(将"作者"替换为"项目",将"书籍"替换为"角色").


Ogr*_*des 9

models.py(联系方式)

class Contact(models.Model)
    first = models.CharField(max_length=30)
    middle = models.CharField('M.I.',max_length=30, blank=True)
    last = models.CharField(max_length=30)
    sort_order = models.PositiveIntegerField(default=99)
Run Code Online (Sandbox Code Playgroud)

models.py(链接)

class Link(models.Model):
    contact = models.ForeignKey(Contact)
    link = models.URLField()
    description = models.CharField(max_length=30)
    access_date = models.DateField(blank=True,null=True)
Run Code Online (Sandbox Code Playgroud)

forms.py

from django.forms import ModelForm
from contacts.models import Contact

class ContactAjaxForm(ModelForm):
    class Meta:
        model=Contact
Run Code Online (Sandbox Code Playgroud)

views.py

def edit(request,object_id=False):
    LinkFormSet = inlineformset_factory(Contact, Link, extra=1)
    if object_id:
        contact=Contact.objects.get(pk=object_id)
    else:
        contact=Contact()
    if request.method == 'POST':
        f=forms.ContactAjaxForm(request.POST, request.FILES, instance=contact)
        fs = LinkFormSet(request.POST,instance=contact)
        if fs.is_valid() and f.is_valid():
            f.save()
            fs.save()
            return HttpResponse('success')
    else:
        f  = forms.ContactAjaxForm(instance=contact)
        fs = LinkFormSet(instance=contact)
    return render_to_response(
        'contacts/edit.html', 
        {'fs': fs, 'f': f, 'contact': contact}
    )
Run Code Online (Sandbox Code Playgroud)

这不是基于本书中的示例,它是从我网站上的一些代码编辑而来的.我没有对它进行测试,所以可能存在一些bug整体而言应该是可靠的.使用一个空的Contact实例不是建议的方法,但它节省了一些逻辑,它的工作原理.

编辑:添加链接模型,切换到正常外键而不是通用外键,这是令人困惑的