javascript - Nested forms with django - Stack Overflow

I have functionality where i need to implement nested django forms with the below modelsclass Publisher

I have functionality where i need to implement nested django forms with the below models

class Publisher(models.Model):
    name = models.CharField(max_length=256)
    address1 = models.CharField(max_length=256)
    address2 = models.CharField(max_length=256)
    city = models.CharField(max_length=256)

class Author(models.Model):
    publisher = models.ForeignKey(Publisher) 
    name = models.CharField(max_length=256)
    address = models.CharField(max_length=256)

class Book(models.Model):
    author = models.ForeignKey(Author)
    name = models.CharField(max_length=256)
    price = models.FloatField()

forms.py

class PublisherForm(ModelForm):
    class Meta:
        model = Publisher

    def __init__(self, *args, **kwargs):

        super(PublisherForm, self).__init__(*args, **kwargs)
        self.fields['name'].widget.attrs = {'id':'inputIcon', 'class':'input-block', 'placeholder':'Publisher Name', 'autofocus':'autofocus'}
        self.fields['address'].widget.attrs = {'id':'inputIcon', 'class':'input-block', 'placeholder':'Publisher Address '}


class AuthorForm(ModelForm):
    class Meta:
        model = Author
        exclude = ('publisher',)    

    def __init__(self, *args, **kwargs):

        super(AuthorForm, self).__init__(*args, **kwargs)
        self.fields['name'].widget.attrs = {'id':'inputIcon', 'class':'input-block', 'placeholder':'Author Name'}
        self.fields['address'].widget.attrs = {'id':'inputIcon', 'class':'input-block', 'placeholder':'Author Address'}

class BookForm(ModelForm):
    class Meta:
        model = Book
        exclude = ('author',)    

    def __init__(self, *args, **kwargs):

        super(BookForm, self).__init__(*args, **kwargs)
        self.fields['name'].widget.attrs = {'id':'inputIcon', 'class':'input-block', 'placeholder':'Book Name'}
        self.fields['price'].widget.attrs = {'id':'inputIcon', 'class':'input-block', 'placeholder':'Book Price'}

So with the above models and forms, i need to create the forms dynamically on the same screen like in the UI screen below

So from the above screen, we can observe all the three model forms should displayon the same page.

1. The publisher may have many authors
2. Each author may have many books

Also you can observe from the design, we have two button for

1.Add Another Author -  Adding Multiple Authors
2.Add Book - Adding multiple books for Author

2. Add Book

When we click on Add Book, a new Book form should be created as in the screenshot

1. Add another Author

When we click on Add another author button a new Author record should be displayed and he can able to add multiple Books for this author same as above by clicking on Add Book

If we have only two models A and B, and if B has ForeignKey to A, then we could be able to achive this functionlaity by usign django formsets or inline_formsets or model_formsets , but here in the above we should be able to

  1. Add nested(multiple) Book forms for Author
  2. Add nested(multiple) Author forms for Publisher

So how to achieve the above functionality ?, i have searched a lot, but could n't able to figure out the above stuff

I have functionality where i need to implement nested django forms with the below models

class Publisher(models.Model):
    name = models.CharField(max_length=256)
    address1 = models.CharField(max_length=256)
    address2 = models.CharField(max_length=256)
    city = models.CharField(max_length=256)

class Author(models.Model):
    publisher = models.ForeignKey(Publisher) 
    name = models.CharField(max_length=256)
    address = models.CharField(max_length=256)

class Book(models.Model):
    author = models.ForeignKey(Author)
    name = models.CharField(max_length=256)
    price = models.FloatField()

forms.py

class PublisherForm(ModelForm):
    class Meta:
        model = Publisher

    def __init__(self, *args, **kwargs):

        super(PublisherForm, self).__init__(*args, **kwargs)
        self.fields['name'].widget.attrs = {'id':'inputIcon', 'class':'input-block', 'placeholder':'Publisher Name', 'autofocus':'autofocus'}
        self.fields['address'].widget.attrs = {'id':'inputIcon', 'class':'input-block', 'placeholder':'Publisher Address '}


class AuthorForm(ModelForm):
    class Meta:
        model = Author
        exclude = ('publisher',)    

    def __init__(self, *args, **kwargs):

        super(AuthorForm, self).__init__(*args, **kwargs)
        self.fields['name'].widget.attrs = {'id':'inputIcon', 'class':'input-block', 'placeholder':'Author Name'}
        self.fields['address'].widget.attrs = {'id':'inputIcon', 'class':'input-block', 'placeholder':'Author Address'}

class BookForm(ModelForm):
    class Meta:
        model = Book
        exclude = ('author',)    

    def __init__(self, *args, **kwargs):

        super(BookForm, self).__init__(*args, **kwargs)
        self.fields['name'].widget.attrs = {'id':'inputIcon', 'class':'input-block', 'placeholder':'Book Name'}
        self.fields['price'].widget.attrs = {'id':'inputIcon', 'class':'input-block', 'placeholder':'Book Price'}

So with the above models and forms, i need to create the forms dynamically on the same screen like in the UI screen below

So from the above screen, we can observe all the three model forms should displayon the same page.

1. The publisher may have many authors
2. Each author may have many books

Also you can observe from the design, we have two button for

1.Add Another Author -  Adding Multiple Authors
2.Add Book - Adding multiple books for Author

2. Add Book

When we click on Add Book, a new Book form should be created as in the screenshot

1. Add another Author

When we click on Add another author button a new Author record should be displayed and he can able to add multiple Books for this author same as above by clicking on Add Book

If we have only two models A and B, and if B has ForeignKey to A, then we could be able to achive this functionlaity by usign django formsets or inline_formsets or model_formsets , but here in the above we should be able to

  1. Add nested(multiple) Book forms for Author
  2. Add nested(multiple) Author forms for Publisher

So how to achieve the above functionality ?, i have searched a lot, but could n't able to figure out the above stuff

Share Improve this question edited Nov 27, 2013 at 7:00 Shiva Krishna Bavandla asked Nov 26, 2013 at 13:59 Shiva Krishna BavandlaShiva Krishna Bavandla 26.8k77 gold badges198 silver badges315 bronze badges 1
  • Replace Charfield by CharField and Foreignkey by ForeignKey in your code sample – juliocesar Commented Nov 26, 2013 at 15:41
Add a ment  | 

1 Answer 1

Reset to default 10

This can be done by playing with inline formsets, in the view of create a publisher, returns the authors and books formsets (using differente prefix parameters for each forms), then use javascript to add new forms empty forms for books and authors.

Bellow is a basic sample I coded for you.

The trick is to use javascript to generate book formsets in templates with dynamic form prefixes related to the parent author (books_formset_0, books_formset_1, ...), then on sumbit the form, iterate for each author to find the related book_formset.

A plete django project to run and test this code can be downloaded here.

IMPORTANT: The following code hasn't been optimized and not use some standards tools like js templates, ajax, etc, but it works and shows how to solve the problem.

template.py:

<script type="text/javascript" src="{{ STATIC_URL }}js/jquery.js"></script>
<script type="text/javascript">
    $(function () {
        $('form').delegate('.btn_add_book', 'click', function () {
            var $this = $(this)
            var author_ptr = $this.attr('id').split('-')[1]
            var $total_author_books = $(':input[name=books_formset_' + author_ptr + '-TOTAL_FORMS]');
            var author_book_form_count = parseInt($total_author_books.val())
            $total_author_books.val(author_book_form_count + 1)

            var $new_book_form = $('<fieldset class="author_book_form">' +
                '<legend>Book</legend>' +
                '<p>' +
                '<label for="id_books_formset_' + author_ptr + '-' + author_book_form_count + '-name">Name:</label>' +
                '<input id="id_books_formset_' + author_ptr + '-' + author_book_form_count + '-name" maxlength="256" name="books_formset_' + author_ptr + '-' + author_book_form_count + '-name" type="text" />' +
                '<input id="id_books_formset_' + author_ptr + '-' + author_book_form_count + '-author" name="books_formset_' + author_ptr + '-' + author_book_form_count + '-author" type="hidden" />' +
                '<input id="id_books_formset_' + author_ptr + '-' + author_book_form_count + '-id" name="books_formset_' + author_ptr + '-' + author_book_form_count + '-id" type="hidden" />' +
                '</p>' +
                '</fieldset>'
            )

            $this.parents('.author_form').find('.author_books').prepend($new_book_form)
        })

        $('form').delegate('#btn_add_author', 'click', function () {
            var $total_authors = $(':input[name=authors_formset-TOTAL_FORMS]');
            author_form_count = parseInt($total_authors.val())
            $total_authors.val(author_form_count + 1)

            book_form = '<fieldset class="author_book_form">' +
                '<legend>Book</legend>' +
                '<p>' +
                '<label for="id_books_formset_' + author_form_count + '-0-name">Name:</label>' +
                '<input id="id_books_formset_' + author_form_count + '-0-name" maxlength="256" name="books_formset_' + author_form_count + '-0-name" type="text" />' +
                '<input id="id_books_formset_' + author_form_count + '-0-author" name="books_formset_' + author_form_count + '-0-author" type="hidden" />' +
                '<input id="id_books_formset_' + author_form_count + '-0-id" name="books_formset_' + author_form_count + '-0-id" type="hidden" />' +
                '</p>' +
                '</fieldset>';

            $new_author_form = $(
                '<fieldset class="author_form">' +
                '<legend>Author</legend>' +
                '<p>' +
                '<label for="id_authors_formset-' + author_form_count + '-name">Name:</label>' +
                '<input id="id_authors_formset-' + author_form_count + '-name" maxlength="256" name="authors_formset-' + author_form_count + '-name" type="text" />' +
                '<input id="id_authors_formset-' + author_form_count + '-publisher" name="authors_formset-' + author_form_count + '-publisher" type="hidden" />' +
                '<input id="id_authors_formset-' + author_form_count + '-id" name="authors_formset-' + author_form_count + '-id" type="hidden" />' +
                '</p>' +
                '<p><input type="button" value="Add Book" class="btn_add_book" id="author-' + author_form_count + '"/></p>' +
                '<div class="author_books">' +
                '<input id="id_books_formset_' + author_form_count + '-TOTAL_FORMS" name="books_formset_' + author_form_count + '-TOTAL_FORMS" type="hidden" value="1" />' +
                '<input id="id_books_formset_' + author_form_count + '-INITIAL_FORMS" name="books_formset_' + author_form_count + '-INITIAL_FORMS" type="hidden" value="0" />' +
                '<input id="id_books_formset_' + author_form_count + '-MAX_NUM_FORMS" name="books_formset_' + author_form_count + '-MAX_NUM_FORMS" type="hidden" value="1000" />' +
                book_form +
                '</div >' +
                '</fieldset >'
            )

            $('#authors').prepend($new_author_form)
        })
    })
</script>
<h1>Add Publisher</h1>
<form action="" method="post">
    {% csrf_token %}
    {{ form.as_p }}

    <p><input type="button" id="btn_add_author" value="Add another author"/></p>

    <div id="authors">
        {{ authors_formset.management_form }}
        {% for form in authors_formset %}
            <fieldset class="author_form">
                <legend>Author</legend>
                {{ form.as_p }}
                <p><input type="button" value="Add Book" class="btn_add_book" id="author-{{ forloop.counter0 }}"/></p>

                <div class="author_books">
                    {{ books_formset.management_form }}
                    {% for form in books_formset %}
                        <fieldset class="author_book_form">
                            <legend>Book</legend>
                            {{ form.as_p }}
                        </fieldset>
                    {% endfor %}
                </div>
            </fieldset>
        {% endfor %}
    </div>
    <p><input type="submit" value="Save"></p>
</form>

forms.py:

AuthorInlineFormSet = inlineformset_factory(Publisher, Author, extra=1, can_delete=False)
BookInlineFormSet = inlineformset_factory(Author, Book, extra=1, can_delete=False)

views.py:

class PublisherCreateView(CreateView):
    model = Publisher

    def form_valid(self, form):
        result = super(PublisherCreateView, self).form_valid(form)

        authors_formset = AuthorInlineFormSet(form.data, instance=self.object, prefix='authors_formset')
        if authors_formset.is_valid():
            authors = authors_formset.save()

        authors_count = 0
        for author in authors:
            books_formset = BookInlineFormSet(form.data, instance=author, prefix='books_formset_%s' % authors_count)
            if books_formset.is_valid():
                books_formset.save()
            authors_count += 1

        return result

    def get_context_data(self, **kwargs):
        context = super(PublisherCreateView, self).get_context_data(**kwargs)
        context['authors_formset'] = AuthorInlineFormSet(prefix='authors_formset')
        context['books_formset'] = BookInlineFormSet(prefix='books_formset_0')
        return context

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1743659700a4485978.html

相关推荐

  • javascript - Nested forms with django - Stack Overflow

    I have functionality where i need to implement nested django forms with the below modelsclass Publisher

    1天前
    30

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信