I'm creating a forum app in django. A user can reply to a Thread by pressing a button. This takes them to a new page containing a form with a textbox to post their reply. The PK of the thread being replied to is passed it through the url and saved as the parent_post of the reply within the CreateView.
This all works fine (so far...) but I also want to display the title of the thread that is being replied to at the top of the page, but I can't seem to be able to use this passed in pk to display the title of the thread at the top of the html page.
URLS:
path('reply/<int:pk>/', NewReplyView.as_view(), name='new-reply'),
View:
class NewReplyView(generic.CreateView):
form_class = NewReplyForm
initial = {'key': 'value'}
template_name = 'forum_app/new_reply.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['x'] = "hahaaha"
p = Post.objects.get(pk=self.kwargs.get('pk')) # Why does this not work, seems to work in the def post() method
context['thread'] = p
return context
def get(self, request, *args, **kwargs):
form = self.form_class(initial=self.initial)
return render(request, self.template_name, {'form':form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
submission = form.save(commit=False)
submission.author = request.user
submission.parent_post = Post.objects.get(pk=self.kwargs.get('pk'))
submission.save()
#return redirect(to='/') # TODO: redirect to newly created thread
return redirect(reverse('forum_app:thread-detail', kwargs={'pk': self.kwargs['pk']}))
#return redirect(reverse_lazy('forum_app:thread-list'))
return render(request, self.template_name, {'form': form})
Template:
{% extends 'base.html'%}
{% block breadcrumb %}
<li class="breadcrumb-item"><a href="{% url 'home' %}">Home</a></li>
<li class="breadcrumb-item"><a href="{% url 'forum_app:thread-list' %}">Threads</a></li>
<li class="breadcrumb-item active" aria-current="New Reply">New Reply</li>
{% endblock %}
<p>{{thread.post_title}}</p>
{% block content %}
<h5>Reply to thread: {{x}}</h5>
<form method='POST'>
{% csrf_token%}
{{form}}
<button class="btn-outline-primary btn-lg" name="submit_post" type="submit">Submit</button>
</form>
{% endblock %}
I even tried putting a random string into the context, but it didn't work, something like this:
class ThreadDetailView(generic.DetailView):
context_object_name = "post"
queryset = Post.objects.all()
template_name = 'forum_app/thread_detail.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['replies'] = Post.objects.filter(parent_post=self.object)
context['c'] = "hahag"
return context
The "hahag" passed into the context in this example works. I can just put <p>{{c}}</p>
at the top of the template and it shows up.
The problem is in how you are handling the get request.. You are only rendering the form without any additional context being passed..(The only thing available in your context is the form and additional stuffs passed by context processors such as the request,user,...) CBVs are kinda tricky. You have to know which method to override, and in many cases you have to call the parent method using super() so as to keep the flow (Not always the case).
First,remove this code-block
def get(self, request, *args, **kwargs):
form = self.form_class(initial=self.initial)
return render(request, self.template_name, {'form':form})
To pass initial values use
def get_initial(self):
initial=super().get_initial()
initial.update({'key': 'value'})
return initial
Same for post method override the form_valid method instead
def form_valid(self, form):
submission=form.instance
submission.author = request.user
submission.parent_post = Post.objects.get(pk=self.kwargs.get('pk'))
return super().form_valid(form)
For redirecting after a successful form submission, you can either set success_url using reverse_lazy, or override the get_success_url method:
The new CreateView fully could be rewritten as
class NewReplyView(generic.CreateView):
form_class = NewReplyForm
initial = {"key": "value"}
template_name = "forum_app/new_reply.html"
success_url = reverse_lazy('namespace:url-name')#For simple urls
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["x"] = "hahaaha"
p = Post.objects.get(
pk=self.kwargs.get("pk")
) # Why does this not work, seems to work in the def post() method
context["thread"] = p
return context
def get_initial(self):
initial=super().get_initial()
initial.update({'key': 'value'})
return initial
def form_valid(self, form):
submission=form.instance
submission.author = request.user
submission.parent_post = Post.objects.get(pk=self.kwargs.get('pk'))
return super().form_valid(form)
def get_success_url(self):#OR use this if complex url pattern or to perform some logic before redirect
return reverse('namespace:url-name', kwargs={'pk': self.object.pk})