Problem with mixing Detail View and Form Mixin django
Asked Answered
B

1

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
Batty answered 6/3, 2021 at 8:18 Comment(0)
T
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})
Tristatristam answered 6/3, 2021 at 8:23 Comment(13)
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.Batty
@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.eTristatristam
@KevinHudgens FormMixin does not save the object. You would have to override form_valid. Or perhaps better yet use ModelFormMixin.Boardman
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.Batty
@KevinHudgens: aaarrrgghhh... I somehow misread this as ModelFormMixin. Updated.Tristatristam
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.Harmonic
@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: docs.djangoproject.com/en/4.0/topics/forms/…Tristatristam
I printed the errors in the view, <ul class="errorlist"><li>myOneToOneField<ul class="errorlist"><li>This field is required.</li></ul></li></ul>. 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?Harmonic
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 <ul class="errorlist"><li> myOneToOneField <ul class="errorlist"><li>This field is required.</li></ul></li></ul>Harmonic
The problem is, I'm trying to update my model, not create a new one.Harmonic
I got it solved now, by only using the post function. #11337048, 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.Harmonic
@AnonymousUser: in that case you swap the self.object = ... and form = ....Tristatristam
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.Harmonic

© 2022 - 2024 — McMap. All rights reserved.