Django edit form based on add form?

I’ve made a nice form, and a big complicated ‘add’ function for handling it. It starts like this…

def add(req):
    if req.method == 'POST':
        form = ArticleForm(req.POST)
        if form.is_valid():
            article = form.save(commit=False)
            article.author = req.user
            # more processing ...

Now I don’t really want to duplicate all that functionality in the edit() method, so I figured edit could use the exact same template, and maybe just add an id field to the form so the add function knew what it was editing. But there’s a couple problems with this

  1. Where would I set article.id in the add func? It would have to be after form.save because that’s where the article gets created, but it would never even reach that, because the form is invalid due to unique constraints (unless the user edited everything). I can just remove the is_valid check, but then form.save fails instead.
  2. If the form actually is invalid, the field I dynamically added in the edit function isn’t preserved.

So how do I deal with this?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

If you are extending your form from a ModelForm, use the instance keyword argument. Here we pass either an existing instance or a new one, depending on whether we’re editing or adding an existing article. In both cases the author field is set on the instance, so commit=False is not required. Note also that I’m assuming only the author may edit their own articles, hence the HttpResponseForbidden response.

from django.http import HttpResponseForbidden
from django.shortcuts import get_object_or_404, redirect, render, reverse


@login_required
def edit(request, id=None, template_name='article_edit_template.html'):
    if id:
        article = get_object_or_404(Article, pk=id)
        if article.author != request.user:
            return HttpResponseForbidden()
    else:
        article = Article(author=request.user)

    form = ArticleForm(request.POST or None, instance=article)
    if request.POST and form.is_valid():
        form.save()

        # Save was successful, so redirect to another page
        redirect_url = reverse(article_save_success)
        return redirect(redirect_url)

    return render(request, template_name, {
        'form': form
    })

And in your urls.py:

(r'^article/new/$', views.edit, {}, 'article_new'),
(r'^article/edit/(?P<id>d+)/$', views.edit, {}, 'article_edit'),

The same edit view is used for both adds and edits, but only the edit url pattern passes an id to the view. To make this work well with your form you’ll need to omit the author field from the form:

class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article
        exclude = ('author',)

Method 2

You can have hidden ID field in form and for edit form it will be passed with the form for add form you can set it in req.POST e.g.

formData =  req.POST.copy()
formData['id'] = getNewID()

and pass that formData to form


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x