3

I am trying to create a comment system for the blog portion of my app with Django. I have attempted to mix my detail view with the form mixin and I'm struggling a bit. When the form is submitted, it doesn't save and no error is present. If any of you can help I would greatly appreciate it.

Here is my View

class DetailPostView(FormMixin, DetailView):
    model = Post
    template_name = "blog/post_detail.html"
    context_object_name = "posts"
    form_class = CommentForm

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["form"] = CommentForm
        return context

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        form = self.get_form()
        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

    def get_success_url(self):
        return reverse("post-detail", kwargs={"pk": self.object.pk})

The model

class Comment(models.Model):
    comment = models.ForeignKey(Post, on_delete=models.CASCADE)
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.CharField(max_length=50)
    created_on = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-created_on"]

    def __str__(self):
        return self.title
Kevin H
  • 127
  • 1
  • 7

1 Answers1

5

The reason that this happens is because you construct a new form that you pass to the context data, as a result, it will not render any errors, since you construct a form without validating the request data and render that form, you thus do not display the form that rejected the data in the first place.

But you do not need to do that. Django's FormMixin [Django-doc] already takes care of that. You thus should not override the .get_context_data(…) method [Django-doc].

Another problem is that you did not save your form, you can override a the form_valid method, or you can inherit from ModelFormMixin [Django-doc].

Finally you better first create the form, and then assign self.object, otherwise it will pass this as an instance to the form:

from django.views.generic.edit import ModelFormMixin

class DetailPostView(ModelFormMixin, DetailView):
    model = Post
    template_name = 'blog/post_detail.html'
    context_object_name = 'posts'
    form_class = CommentForm

    # no get_context_data override

    def post(self, request, *args, **kwargs):
        # first construct the form to avoid using it as instance
        form = self.get_form()
        self.object = self.get_object()
        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

    def get_success_url(self):
        return reverse('post-detail', kwargs={'pk': self.object.pk})
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Thank you, Willem, I have edited my view to reflect what you have described here. But when checking into my Django admin portal. The comment has not been saved. – Kevin H Mar 06 '21 at 08:33
  • 1
    @KevinHudgens: no, but that is because the form is *invalid*. But you simply have "overwritten" that form with a new, and therefore it does not render the errors in the templat.e – Willem Van Onsem Mar 06 '21 at 08:34
  • 1
    @KevinHudgens `FormMixin` does not save the object. You would have to override `form_valid`. Or perhaps better yet use `ModelFormMixin`. – Abdul Aziz Barkat Mar 06 '21 at 08:34
  • Again thanks. I will look into both of your suggested methods to save the form. I appreciate your help on this question and my previous Django posts. – Kevin H Mar 06 '21 at 08:38
  • @KevinHudgens: aaarrrgghhh... I somehow misread this as `ModelFormMixin`. Updated. – Willem Van Onsem Mar 06 '21 at 08:39
  • When I sumbit, it updates the page with the new value, but when I reload the page I get the same value as before I submitted. And I checked in the admin, and I still have the same value as I had before submitting. So it's not working. – AnonymousUser Mar 15 '22 at 07:37
  • 1
    @AnonymousUser: likely that is because the form was invalid. So then it rerenders with the values. Do you render the errors of the form properly: https://docs.djangoproject.com/en/4.0/topics/forms/#rendering-fields-manually – Willem Van Onsem Mar 15 '22 at 08:02
  • I printed the errors in the view, `
    • myOneToOneField
      • This field is required.
    `. So it seems like I need to add to the OneToOneField, but I don't want to change the OneToOneField, I want to keep the value it already have. So how can I add `self.request.user`?
    – AnonymousUser Mar 16 '22 at 04:22
  • I read now your answer more carefully, and saw that my `form` was under `self.object` in the post function. Now when I tap submit, it stays 0, if I submit with 5. But still I have `
    • myOneToOneField
      • This field is required.
    `
    – AnonymousUser Mar 16 '22 at 05:03
  • The problem is, I'm trying to update my model, not create a new one. – AnonymousUser Mar 16 '22 at 07:13
  • I got it solved now, by only using the post function. https://stackoverflow.com/questions/11336548/django-taking-values-from-post-request, The bad thing was, on the post function I had to add all the context again, since the get_context_data stopped working when I did `return render`. – AnonymousUser Mar 16 '22 at 07:51
  • 1
    @AnonymousUser: in that case you swap the `self.object = ...` and `form = ...`. – Willem Van Onsem Mar 16 '22 at 07:54
  • I'm back to this issue, and this time it's not Updating the object. I have tried a **UpdateView**, but since I was using a form for a different model, I weren’t able to use that. – AnonymousUser Jun 06 '22 at 06:43