pythondjangomixinsdetailsview

Problem with mixing Detail View and Form Mixin django


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

Solution

  • 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})