django - inlineformset_factory 创建新对象并在创建后编辑对象

标签 django inline-formset

在 django 文档中,有一个使用 inlineformset_factory 编辑已创建的对象的示例

https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#using-an-inline-formset-in-a-view

我将示例更改为这样:

def manage_books(request):
    author = Author()
    BookInlineFormSet = inlineformset_factory(Author, Book, fields=('title',))
    if request.method == "POST":
        formset = BookInlineFormSet(request.POST, request.FILES, instance=author)
        if formset.is_valid():
            formset.save()
            return HttpResponseRedirect(author.get_absolute_url())
    else:
        formset = BookInlineFormSet(instance=author)
    return render_to_response("manage_books.html", {
        "formset": formset,
    })

通过上述内容,它仅渲染内联模型,而不渲染父模型。

要使用 inlineformset_factory 创建一个新对象(例如作者),并关联多本书,方法是什么?

使用 django 文档中的上述作者书模型的示例将会很有帮助。 django 文档仅提供了如何使用 inlineformset_factory 编辑已经创建的对象的示例,但没有创建新的

最佳答案

我已经使用 Django 基于类的 View 做到了这一点。

这是我的方法:

models.py

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)


class Book(models.Model):
    author = models.ForeignKey(Author)
    title = models.CharField(max_length=100)

forms.py

from django.forms import ModelForm
from django.forms.models import inlineformset_factory

from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Fieldset

from .models import Author, Book

class AuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = ('name', )

    @property
    def helper(self):
        helper = FormHelper()
        helper.form_tag = False # This is crucial.

        helper.layout = Layout(
            Fieldset('Create new author', 'name'),
        )

        return helper


class BookFormHelper(FormHelper):
    def __init__(self, *args, **kwargs):
        super(BookFormHelper, self).__init__(*args, **kwargs)
        self.form_tag = False
        self.layout = Layout(
            Fieldset("Add author's book", 'title'),
        )


BookFormset = inlineformset_factory(
    Author,
    Book,
    fields=('title', ),
    extra=2,
    can_delete=False,
)

views.py

from django.views.generic import CreateView
from django.http import HttpResponseRedirect

from .forms import AuthorForm, BookFormset, BookFormHelper
from .models import Book, Author

class AuthorCreateView(CreateView):
    form_class = AuthorForm
    template_name = 'library/manage_books.html'
    model = Author
    success_url = '/'

    def get(self, request, *args, **kwargs):
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        book_form = BookFormset()
        book_formhelper = BookFormHelper()

        return self.render_to_response(
            self.get_context_data(form=form, book_form=book_form)
        )

    def post(self, request, *args, **kwargs):
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        book_form = BookFormset(self.request.POST)

        if (form.is_valid() and book_form.is_valid()):
            return self.form_valid(form, book_form)

        return self.form_invalid(form, book_form)

    def form_valid(self, form, book_form):
        """
        Called if all forms are valid. Creates a Author instance along
        with associated books and then redirects to a success page.
        """
        self.object = form.save()
        book_form.instance = self.object
        book_form.save()

        return HttpResponseRedirect(self.get_success_url())

    def form_invalid(self, form, book_form):
        """
        Called if whether a form is invalid. Re-renders the context
        data with the data-filled forms and errors.
        """
        return self.render_to_response(
            self.get_context_data(form=form, book_form=book_form)
        )

    def get_context_data(self, **kwargs):
        """ Add formset and formhelper to the context_data. """
        ctx = super(AuthorCreateView, self).get_context_data(**kwargs)
        book_formhelper = BookFormHelper()

        if self.request.POST:
            ctx['form'] = AuthorForm(self.request.POST)
            ctx['book_form'] = BookFormset(self.request.POST)
            ctx['book_formhelper'] = book_formhelper
        else:
            ctx['form'] = AuthorForm()
            ctx['book_form'] = BookFormset()
            ctx['book_formhelper'] = book_formhelper

        return ctx

urls.py

from django.conf.urls import patterns, url
from django.views.generic import TemplateView

from library.views import AuthorCreateView

urlpatterns = patterns('',
    url(r'^author/manage$', AuthorCreateView.as_view(), name='handle-books'),
    url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'),
)

ma​​nage_books.html

{% load crispy_forms_tags %}

<head>
  <!-- Latest compiled and minified CSS -->
  <link rel="stylesheet"
    href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
</head>

<div class='container'>
  <form method='post'>
    {% crispy form %}
    {{ book_form.management_form }}
    {{ book_form.non_form_errors }}

    {% crispy book_form book_formhelper %}
    <input class='btn btn-primary' type='submit' value='Save'>
  </form>
<div>

注意:

  • 这是一个使用inlineformset_factory的简单可运行示例 功能和 Django 通用基于类的 View
  • 我假设 django-crispy-forms 已安装,并且正确 配置完毕。
  • 代码存储库托管于:https://bitbucket.org/slackmart/library_example

我知道所展示的解决方案需要更多代码,但是开始使用 Django 基于类的 View 非常棒。

关于django - inlineformset_factory 创建新对象并在创建后编辑对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29758558/

相关文章:

python - Django注册模块

python - Django 异常和响应代码列表

python - angularjs 最快/最简单的后端?

django - Django 中的自定义表单集模板

python - Openshift:OSError Errno 98 无法更新服务器

python - 在 Django 单元测试中使用 mock 修补 celery 任务

python - 没有实例的 Django Formset

python - 在非父模型的内联表单集中更改模型字段的查询集

python - Django:动态内联表单,根据用户选择进行过滤

django - 如何限制 django admin 内联表单集