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.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
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.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.