Reputation: 139
I have a model Book and a model Review (with a ForeignKey to Book). I wanted to create a view where you have all the data related to a book (DetailView), and add the functionality of showing and creating reviews. I came up with this code, but don't know whether it is a good practice, maybe I should go for something different:
class BookDetailView(CreateView):
template_name = 'books/book_detail.html'
form_class = ReviewForm
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
slug = self.kwargs.get('slug')
obj = Book.objects.get(slug__iexact=slug)
if get_language() == 'es':
context['reviews'] = obj.review_set.all().filter(language__iexact='es')
else:
context['reviews'] = obj.review_set.all().filter(language__iexact='en')
if len(context['reviews']) == 0:
context['is_empty'] = True
context['object'] = obj
return context
def form_valid(self, form):
obj = form.save(commit=False)
return super().form_valid(form)
And the template:
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<h1>{{object.title}}</h1>
<h2>{% trans "Reviews section" %}</h2>
{% for review in reviews %}
<b>{{review.title}}
{% endfor %}
<h2>Add a review!</h2>
{% include "form.html" with form=form %}
{% endblock content %}
And finally the url: url(r'^(?P[\w-]+)/$', ...)
What do you think?
Thanks for your time!
Upvotes: 2
Views: 767
Reputation: 490
I know this post is a little bit old but it helps me a lot with my issue. Thank you @allcaps
First of all, I would like to mention that the "ReviewForm" should inherit from forms.ModelForm and than we will have a access to "instance" and "save()"
More about ModelForm you can read in django docs Django ModelForms
Upvotes: 0
Reputation: 11228
I did something similar once. But used the DetailView and just added the ReviewForm to the context and added a method to handle post data. Something like this:
class BookDetailView(DetailView):
model = Book
def get_context_data(self, *args, **kwargs):
ctx = super().get_context_data(*args, **kwargs)
language = get_language()
ctx.update({
'reviews': ctx['book'].review_set.all().filter(language__iexact=language),
'form': ReviewForm()
})
return ctx
def post(self, *args, **kwargs):
self.object = self.get_object(self.get_queryset())
form = ReviewForm(self.request.POST)
if form.is_valid():
form.instance.book = self.object
form.save()
return HttpResponseRedirect(self.object.get_absolute_url())
else:
ctx = self.get_context_data(**kwargs)
ctx.update({'form': form})
return self.render_to_response(ctx)
I guess this takes a little more code for handling the form, but the bonus is you can set the related book (the user can't fiddle with that form data).
Note that you don't have to specify template_name
because it is automagical correct.
Upvotes: 4