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

发布于 2024-07-26 05:35:20 字数 461 浏览 4 评论 0原文

[我已将其发布在 Django 用户 | Google 网上论坛也。]

使用 中的示例内联表单集文档,我能够编辑属于特定模型的对象(使用 模型)。 我一直在尝试遵循相同的模式 使用内联表单集创建新对象,但无法 我的头脑足够清醒,可以为此目的提出一个工作观点。

使用与上面链接中相同的示例,我将如何进行 创建“Author”模型的新实例及其相关模型 “书”对象?

[I have posted this at the Django users | Google Groups also.]

Using the example in the inline formset docs, I am able to edit objects belonging a particular model (using
modelforms). I have been trying to follow the same pattern for
creating new objects using inline formsets, but have been unable to
clear my head enough to bring out a working view for this purpose.

Using the same example as in the above link, how would I go about
creating a new instance of an "Author" model together with its related
"Book" objects?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

佞臣 2024-08-02 05:35:20

首先,创建一个作者模型表单。

author_form = AuthorModelForm()

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

author = Author()

然后使用虚拟作者创建一个内联表单集,如下所示:

formset = BookFormSet(instance=author)  #since author is empty, this formset will just be empty forms

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

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

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

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

编辑:

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

{% 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 %}

First, create a Author model form.

author_form = AuthorModelForm()

then create a dummy author object:

author = Author()

Then create a inline formset using the dummy author like so:

formset = BookFormSet(instance=author)  #since author is empty, this formset will just be empty forms

Send that off to a template. After the data is returned back to the view, you create the Author:

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

Now hook the inline formset in with the newly created author and then save:

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

edit:

To have no checkboxes on new forms, do this is a template:

{% 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 %}
请持续率性 2024-08-02 05:35:20

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

假设您没有在 if-else 语句之外创建空的created_author,因此需要将表单集嵌套在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:
    ...

执行以下操作:

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:
    ...

此版本避免提交created_author,直到book_formset 有机会进行验证。 需要纠正的用例是,有人使用无效的 BookFormSet 填写了有效的 AuthorForm,并不断重新提交,从而创建了多个没有与其关联的书籍的作者记录。 这似乎适用于我的项目跟踪应用程序(将“作者”替换为“项目”,将“书籍”替换为“角色”)。

I'd actually like to propose a small adjustment to nbv4's solution:

Assume that you don't create the empty created_author outside of the if-else statement and thus need to nest the formset inside the author_form.is_valid() to avoid runtime errors when the author_form is not valid (and thus no created_author is instantiated).

Instead of:

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:
    ...

Do the following:

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:
    ...

This version avoids committing the created_author until the book_formset has had a chance to validate. The use case to correct for is that someone fills out a valid AuthorForm with an invalid BookFormSet and keeps resubmitting, creating multiple Author records with no Books associated with them. This seems to work for my project-tracker app (replace "Author" with "Project" and "Book" with "Role").

櫻之舞 2024-08-02 05:35:20

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)

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)

forms.py

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

class ContactAjaxForm(ModelForm):
    class Meta:
        model=Contact

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}
    )

这不是基于书中的示例,它是根据我网站上的一些代码进行编辑的。 我还没有测试过它,所以可能会有一些错误,但总的来说它应该是可靠的。 使用 Contact 的空实例不是建议的方法,但它节省了一些逻辑并且可行。

编辑:添加了链接模型,切换为普通外键而不是令人困惑的通用外键

models.py (Contact)

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)

models.py (Link)

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)

forms.py

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

class ContactAjaxForm(ModelForm):
    class Meta:
        model=Contact

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}
    )

This is not based on the example in the book, it's edited down from some code on my site. I haven't tested it so there might be some bugs but overall it should be solid. Using an empty instance of Contact isn't the suggested method but it saves a bit of logic and it works.

Edit: Added Link Model, switched to normal Foreign Key instead of Generic Foreign Key which is confusing

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文