inlineformset_factory create new objects and edit objects after created

前端 未结 4 1408
说谎
说谎 2020-12-13 07:53

In the django docs, there\'s an example of using inlineformset_factory to edit already created objects

https://docs.djangoproject.com/en/dev/topics/forms/mo

4条回答
  •  青春惊慌失措
    2020-12-13 08:08

    I've done that using Django Class-Based Views.

    Here's my approach:

    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'),
    )
    

    manage_books.html

    {% load crispy_forms_tags %}
    
    
      
      
    
    
    
    {% crispy form %} {{ book_form.management_form }} {{ book_form.non_form_errors }} {% crispy book_form book_formhelper %}

    Notice:

    • This is a simple runable example that use the inlineformset_factory feature and Django generic Class-Based Views
    • I'm assumming django-crispy-forms is installed, and it's properly configured.
    • Code repository is hosted at: https://bitbucket.org/slackmart/library_example

    I know it's more code that the showed solutions, but start to using Django Class-Based Views is great.

提交回复
热议问题