Re: properly passing form post data to get_context_data() in detailview

1,278 views
Skip to first unread message

Greg Maruszeczka

unread,
Jun 7, 2013, 6:56:51 PM6/7/13
to django...@googlegroups.com
I believe I've found my own solution and it seems more straightforward than I originally thought. I'm posting it here in the chance it saves someone else some time. When django told me there was no attribute 'object' it set me to look at where this attribute was supposed to be assigned and I found it in the inherited class' methods.

Anyway, after some refactoring, trial-and-error and reading code I've revised the view to this:

class PostDetailView(DetailView):
    template_name = 'blog_detail.html'
    context_object_name = 'post'
    form_class = CommentForm
        
    def get_object(self):
        post = Post.objects.get(published=True, slug=self.kwargs['slug'])
        return post
    
    def get_context_data(self, **kwargs):
        context = super(PostDetailView, self).get_context_data(**kwargs)
        context['comments'] = Comment.objects.filter(published=True).filter(post_id=context['post'].id)
        return context
    
    def get(self, request, *args, **kwargs):
        ## important ##
        super(PostDetailView, self).get(self, request, *args, **kwargs)
        form = self.form_class
        return self.render_to_response(self.get_context_data(form=form))
    
    def post(self, request, *args, **kwargs):
        ## important ##
        self.object = self.get_object()
        form = self.form_class(request.POST)
        if form.is_valid():
            f = form.save(commit=False)
            f.post_id = self.object.id
            f.ip_address = self.get_client_ip(self.request)
            f.save()
            form.send_email(self.object)
            messages.add_message(self.request, messages.SUCCESS, 'Comment submitted and will be published pending administrator approval. Thanks!')
            return redirect(self.object)
        else:
            messages.add_message(self.request, messages.ERROR, 'There was a problem with your submission. Please check the form below for errors and try again.')
            return self.render_to_response(self.get_context_data(form=form))
    
    def get_client_ip(self, request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip

The super() call in PostDetailView.get() and the self.object = self.get_object() call in PostDetailView.post() ensures there's a self.object and I no longer get the 'attribute error'. As well empty fields in the submission form are now properly flagged by validation errors. It appears to work as intended and now I can review again in light of best practices. If anyone has suggestions on that I would appreciate it

Thanks,
GM



On Tuesday, 4 June 2013 17:51:24 UTC-7, Greg Maruszeczka wrote:
Hi,

I'm trying to process a form through a detailview that adds a comment to a blog post. Here's my view code:

class PostDetailView(DetailView):
    model = Post
    template_name = 'blog_detail.html'
    queryset = Post.objects.filter(published=True)
    form_class = CommentForm
      
    def get_context_data(self, **kwargs):
        context = super(PostDetailView, self).get_context_data(**kwargs)
        post = self.get_object()
        context['comments'] = Comment.objects.filter(published=True).filter(post_id=post.id)
        context['form'] = CommentForm
        return context
    
    def post(self, request, *args, **kwargs):
        post = self.get_object()
        form = CommentForm(request.POST)
        if form.is_valid():
            f = form.save(commit=False)
            f.post_id = post.id
            f.ip_address = self.get_client_ip(self.request)
            f.save()
            form.send_email()
            messages.add_message(self.request, messages.SUCCESS, 'Comment submitted. Thanks!')
            return HttpResponseRedirect(request.META.get('HTTP_REFERER', None))
        else:
            # this fails with attribute error: 'PostDetailView' object has no attribute 'object'
            return self.render_to_response(self.get_context_data(form=form))
    
    def get_client_ip(self, request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip


And here's the relevant form code:

class CommentForm(ModelForm):
    class Meta:
        model = Comment
        exclude = ('post', 'published')
        
    def send_email(self):
        text = self.cleaned_data['text']
        name = self.cleaned_data['name']
        send_mail(
            'comment submission',
            name + ' wrote:\n' + text,
            [from_email_address],
            ([to_email_address])
        )

Form processing appears to work as expected when the form fields are actually filled and the form is valid but fails with an "Attribute Error: 'PostDetailView' object has no attribute 'object'" when the fields are blank (i.e. form is not valid). As a relative newbie to python and django I'm at a complete loss as to what I'm doing wrong here. 

Thanks in advance for any pointers.
Reply all
Reply to author
Forward
0 new messages