Creating a model and related models with Inline formsets

前端 未结 3 1186
独厮守ぢ
独厮守ぢ 2020-11-28 01:50

[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 belo

相关标签:
3条回答
  • 2020-11-28 02:03

    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 %}
    
    0 讨论(0)
  • 2020-11-28 02:11

    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").

    0 讨论(0)
  • 2020-11-28 02:16

    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

    0 讨论(0)
提交回复
热议问题