MatsuzakaSteven
MatsuzakaSteven

Reputation: 317

How to get an object id in form_valid?

I am trying to make a comment form on a posting app with django, the problem is I can't seem to get it's own object's id, any idea?

#views.py
class MyFormView(FormView):
    form_class = CommentForm
    success_url = "/"

    def form_valid(self,form,*args,**kwargs):
        comment = form.save(commit=False)
        comment.message=Message.objects.get(id=???)
        comment.save()
        return super(MyFormView, self).form_valid(form)
#urls.py
urlpatterns = [
    path('', MessageListView.as_view(),name="messaging-main"),
    path('new', MessageCreateView.as_view(),name="messaging-new"),
    path('post/<int:pk>', MessageDetailView.as_view(),name="messaging-detail"),
    path('my_form',MyFormView.as_view(),name="form-view")
]
#forms.py
class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ['comment']
#models.py
class Message(models.Model):
    date_posted = models.DateTimeField(default=timezone.now)
    message = models.TextField()
    image = models.ImageField(default="")


    def __str__(self):
        return self.message

class Comment(models.Model):
    message = models.ForeignKey(Message,on_delete=models.CASCADE)
    comment = models.TextField(max_length=50)
    date_posted = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return "Comment on {}".format(str(self.date_posted))

    def get_absolute_url(self):
        return reverse("messaging-detail",kwargs={"id":self.id})

If i were to replace the ??? with for example 7, it will post every comment on message(or post) with the id 7, but I want the comment to be posted on the message i am seeing. Any help appreciated

Upvotes: 3

Views: 2567

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477641

You will need to encode the primary key (or another attribute) of the message in the request. You can do that in several ways: by encoding it in the URL that is triggered for example, or by a hidden field in the form that will then be send as a POST parameter.

We can thus for example add a message_id parameter to the url:

#urls.py

urlpatterns = [
    # …,
    path('my_form/<int:message_pk>', MyFormView.as_view(), name="form-view")
]

Then in the form, we can use the parameter, by accessing it in self.kwargs:

#views.py

class MyFormView(FormView):
    form_class = CommentForm
    success_url = "/"

    def form_valid(self,form,*args,**kwargs):
        form.instance.message_id = self.kwargs['message_pk']
        self.object = form.save()
        return super(MyFormView, self).form_valid(form)

By using message_id, we avoid making an extra call to the the database to fetch the corresponding Message.

In the template you render for the MessageDetailView view, the <form> will then need to use as action URL a URL with the corresponding primary key of the message. For example if the context object name is 'message', you can pass it with:

<form action="{% url 'form-view' message_pk=message.pk %}" method="post">
    …
</form>

Upvotes: 3

Related Questions