Giannis
Giannis

Reputation: 5526

Django ModelForm within DetailView

I have a DetailView which displays a Post. I now want to add the ability to create a Comment for a Post. For that I need a CommentForm, within the DetailView, so that I can create comments while being on the same page with a Post.

Is this possible, or should I be looking for another approach, like doing the form handling 'manually'?

class Comment(models.Model):
    body = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    author_name = models.CharField(max_length=255)
    parent_post = models.ForeignKey('Post',related_name='comments')

class PostDetailView(BlogMixin,DetailView):
    """ A view for displaying a single post """
    template_name = 'post.html'
    model = Post
    #Add some code for the CommentForm here?

class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        exclude = ("parent_post","created_at")

    def create_view(request, **kwargs):
        if request.method == "POST":
            parent_fk = request.args['parent_fk'] #Im hoping to find how this will work soon 
            form = CommentForm(request.POST)
            if form.is_valid():
                new_comment = form.save(commit=False)
                new_comment.parent_post = parent_fk
                new_comment.save()
                return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

** Alternative **

I have been trying to apply the solution - A better alternative - but I get

Exception Value: __init__() takes exactly 1 argument (3 given)
Exception Location: .../sitepackages/django/core/handlers/base.py in get_response, line 112

and have not been able to trace it yet.

class PostView(BlogMixin,DetailView):
    """ A view for displaying a single post """
    template_name = 'post.html'
    model = Post
    def get_context_data(self, **kwargs):
        context = super(PostView, self).get_context_data(**kwargs)
        context['form'] = CommentForm()
        return context

class PostDetailView(View):

    def get(self, request, *args, **kwargs):
        view = PostView.as_view()
        return view(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        view = PostComment.as_view()
        return view(request, *args, **kwargs)

class PostComment(  SingleObjectMixin , FormView):
    template_name = 'post.html'
    form_class = CommentForm
    model = Post

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(PostComment, self).post(request, *args, **kwargs)

    def get_success_url(self):
        return reverse('post-detail', kwargs={'pk': self.object.pk})
class BlogMixin(object):
    """
    Basic mixin for all the views. Update the context with additional
    information that is required across the whole site, typically
    to render base.html properly
    """
    def get_context_data(self, *args, **kwargs):
        context = super(BlogMixin, self).get_context_data(*args, **kwargs)
        blog = Blog.get_unique()
        context.update({
            'blog': blog,
            'active_user': users.get_current_user(),
            'is_admin': users.is_current_user_admin()
        })
        return context

urls.py: url(r'^post/(?P[\d]+)/$', views.PostDetailView., name="post-detail"),

Upvotes: 2

Views: 1566

Answers (3)

Giannis
Giannis

Reputation: 5526

In the end I could not make it work with the redirect, but the following is working:

class PostDetailView(BlogMixin,CreateView):
    """ A view for displaying a single post """
    template_name = 'post.html'
    model = Comment
    fields = ['body','author_name'] 
    def get_context_data(self, **kwargs):

        context = super(PostDetailView, self).get_context_data(**kwargs)
        context['post'] =  Post.objects.get(pk=self.kwargs['pk'])
        return context

    def form_valid(self, form):
        # self.object = form.save()
        obj = form.save(commit=False)
        obj.parent_post = Post.objects.get(pk=self.kwargs['pk'])
        obj.save()

        return redirect('post-detail', self.kwargs['pk'])

Upvotes: 0

gamer
gamer

Reputation: 5863

Why dont you send your form in the context in detail view:

class YourDetailView(DetailView):
    #Your stuff here
    def get_context_date(self, **kwargs):
         context = super(YOurDetailView, self).get_context_data(**kwargs)
         context['form'] = YourForm
         return context

PS. Look for the parameters in get_context_date..

Upvotes: 1

MD Islam
MD Islam

Reputation: 137

If you want to use your first method, you can make the FK a hidden field. In your view, you can save the FK before committing the comment to the database. Like this:

if form.is_valid():
    comment = form.save(commit=False)
    comment.parent_post = parent_post
    comment.save()

Edit: If you want to fetch the comments, then you can use filter by post to get a QuerySet of the comments.

Upvotes: 1

Related Questions