Mowli
Mowli

Reputation: 77

How to edit an object using model form in django?

This may possibly be a duplicate of this answer. Currently, i'm working on updating an object using the same model form that is used to create the object.

my views.py looks like: (as from the answer):

def newpost(request):
    form = PostForm(request.POST)
    if request.method == "POST":
        if form.is_valid():
            obj = form.save(commit=False)
            obj.save()
            return redirect('newpost')
    return render(request, 'console/newpost.html', {'form':form})

def editpost(request, pk):
    obj = Post.objects.get(id=pk)
    form = PostForm(instance=obj)
    if request.method == "POST":
        if form.is_valid():
            obj = form.save(commit=False)
            obj.save()
            return redirect('editpost')
    return render(request, 'console/editpost.html', {'form':form})

And my html form in editpost looks like:

<form method="POST" action="{% url 'newpost' %}">
    {% csrf_token %}
    {{form.as_p}}
    <button type="submit"> Submit</button>
</form>

and my urls.py looks like:

path('console/post/', c_views.newpost, name='newpost'),
path('console/post/<int:pk>/', c_views.editpost, name='editpost'),

And the above codes works perfectly fine, but creates a new instance, with the data of the object taken from pk.

I added a obj.delete() code like this:

def editpost(request, pk):
    obj = Post.objects.get(id=pk)
    form = PostForm(instance=obj)
    obj.delete()
    if request.method == "POST":
        if form.is_valid():
            obj = form.save(commit=False)
            obj.save()
            return redirect('editpost')
    return render(request, 'console/editpost.html', {'form':form})

This code gives me the exact thing i wanted, but i know it's not a good practice. My question here is, is this a correct way or am i lagging somewhere. I know the action in my editpost html should not be {% url 'newpost' %}, but if i use {% url 'editpost' %} i don't know how to pass the pk value inside the url tag. Can anyone suggest me the correct way?

Upvotes: 3

Views: 1893

Answers (1)

Iain Shelvington
Iain Shelvington

Reputation: 32244

Each of your views should accept GET and POST methods, when the method is GET the form is instantiated with no request.POST data passed to it and the form is just rendered.

def newpost(request):
    if request.method == 'GET':
        form = PostForm()
    else:  # POST
        form = PostForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('newpost')
    return render(request, 'console/newpost.html', {'form':form})

def editpost(request, pk):
    obj = Post.objects.get(id=pk)
    if request.method == 'GET':
        form = PostForm(instance=obj)
    else:  # POST
        form = PostForm(request.POST, instance=obj)
        if form.is_valid():
            form.save()
            return redirect('editpost')
    return render(request, 'console/editpost.html', {'form':form})

<form method="POST">

If you do not set the "action" attribute on a form it will submit the data to the same URL that the browser is currently on. This way you can use the same template for both views

Upvotes: 1

Related Questions