hey I'm a beginner in django and trying to make a question and answer project using class based views, im trying to make an answer form to write an answer for the question, the posting and all is already good.
but I don't know how to make it so that it posts the answer object to the correct question object in class based views, how do I do this? Please explain in a very simple way for a beginner, thank you!
oh sorry here's the code so far:
views.py:
class AskForm(SuccessMessageMixin , CreateView):
template_name = 'forum/ask-question.html'
model = Question
form_class = QuestionForm
success_message = 'Success!'
def form_valid(self, form):
form.instance.user = self.request.user
form.save()
return super(AskForm, self).form_valid(form)
class AnswerForm(SuccessMessageMixin, CreateView):
template_name = 'forum/answer-question.html'
model = Answer
form_class = AnswerForm
success_message = 'Success!'
def form_valid(self, form):
form.instance.user = self.request.user
form.save()
return super(AskForm, self).form_valid(form)
models.py:
# This is the question model
class Question(VoteModel, models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True)
title = models.CharField(max_length=30)
detail = models.TextField()
tags = models.TextField(default='')
add_time = models.DateTimeField(auto_now_add=True)
def get_absolute_url(self):
return f"/questions/"
def __str__(self):
return self.title
# This is the answer model
class Answer(VoteModel, models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
detail = models.TextField()
add_time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.detail
forms.py:
class QuestionForm(ModelForm):
class Meta:
model = Question
fields = ['title', 'detail', 'tags']
exclude = ('user', 'add_time')
class AnswerForm(ModelForm):
class Meta:
model = Answer
fields = ['detail']
exclude = ('user', 'add_time')
edit 2:
yep so again, trying to make a question and answer project in django and don't know how to tell the answer object which question object to attach to, I'm trying to make it so that I just click answer on the question detail page and it automatically knows that Im trying to send in the answer object to that specific question
traceback:
Environment:
Request Method: POST
Request URL: http://127.0.0.1:8000/answer/
Django Version: 4.0.4
Python Version: 3.8.10
Installed Applications:
['django.contrib.humanize',
'forum',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'crispy_forms',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'users',
'vote']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback (most recent call last):
File "/home/titsnium/.local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/home/titsnium/.local/lib/python3.8/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/titsnium/.local/lib/python3.8/site-packages/django/views/generic/base.py", line 84, in view
return self.dispatch(request, *args, **kwargs)
File "/home/titsnium/.local/lib/python3.8/site-packages/django/views/generic/base.py", line 119, in dispatch
return handler(request, *args, **kwargs)
File "/home/titsnium/.local/lib/python3.8/site-packages/django/views/generic/edit.py", line 184, in post
return super().post(request, *args, **kwargs)
File "/home/titsnium/.local/lib/python3.8/site-packages/django/views/generic/edit.py", line 153, in post
return self.form_valid(form)
File "/home/titsnium/Documents/eduzec/forum/views.py", line 78, in form_valid
_forum = get_object_or_404(Question, id=self.kwargs['pk'])
Exception Type: KeyError at /answer/
Exception Value: 'pk'
urls.py:
from django.urls import path
from . import views
urlpatterns = [
path('questions/', views.QuestionsView.as_view(), name='questions'),
path('ask/', views.AskForm.as_view(), name='ask'),
path('answer/', views.AnswerForm.as_view(), name='answer'),
path('detail/<pk>', views.QuestionDetailView.as_view(), name='detail'),
path('save-text', views.WriteCommentAnswerView.as_view(), name='save-text'),
path('save-vote', views.SaveVoteView.as_view(), name='save-vote'),
]
views.py:
from django.shortcuts import render, get_object_or_404
from django.http import JsonResponse, HttpResponseRedirect
from django.views import View
from django.views.generic.list import ListView
from django.views.generic import DetailView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Count
from requests import request
from .forms import QuestionForm, AnswerForm
from django.contrib.messages.views import SuccessMessageMixin
from django.urls import reverse, reverse_lazy
from . import models
from .models import Question, Answer, Comment
from vote.models import UP, DOWN
from .utilities import cast_vote, save_text_help
class QuestionsView(ListView):
model = Question
template_name = 'forum/questions.html'
context_object_name = "quests"
paginate_by = 5
def get_queryset(self):
qs = super(QuestionsView, self).get_queryset()
search = self.request.GET.get('q')
if search:
qs = qs.filter(title__icontains=search)
qs = qs.order_by("-id")
qs = qs.annotate(count_of_answers=Count('answer'))
return qs
class QuestionDetailView(DetailView):
model = Question
template_name = 'forum/detail.html'
context_object_name = 'quest'
def get_context_data(self, **kwargs):
context = super(QuestionDetailView, self).get_context_data(**kwargs)
context['tags'] = self.object.tags.split(',')
answers = Answer.objects.filter(question=self.object).order_by('-vote_score')
comments = []
for answer in answers:
comments.append(Comment.objects.filter(answer=answer))
context['answers_comments'] = zip(answers, comments)
return context
def get_queryset(self):
qs = super(QuestionDetailView, self).get_queryset()
qs = qs.annotate(count_of_answers=Count('answer'))
return qs
class AskForm(SuccessMessageMixin , CreateView):
template_name = 'forum/ask-question.html'
model = Question
form_class = QuestionForm
success_message = 'Success!'
def form_valid(self, form):
form.instance.user = self.request.user
form.save()
return super(AskForm, self).form_valid(form)
class AnswerForm(SuccessMessageMixin, CreateView):
template_name = 'forum/answer-question.html'
model = Answer
form_class = AnswerForm
success_message = 'Success!'
def form_valid(self, request, form):
_forum = get_object_or_404(Question, id=self.kwargs['pk'])
form.instance.user = self.request.user
form.instance.forum = _forum
return super().form_valid(form)
class WriteCommentAnswerView(View):
def post(self, request):
text=request.POST['text']
id=request.POST['id']
text_type = request.POST['type']
user=request.user
if text_type == "comment":
return render(request, 'forum/includes/single_comment.html', {'comment': save_text_help(text, id, text_type, user)})
else:
return render(request, 'forum/includes/single_answer.html', {'answer': save_text_help(text, id, text_type, user)})
class SaveVoteView(LoginRequiredMixin, View):
def post(self, request):
id = request.POST['id']
user_id = request.user.id
vote_to = request.POST['vote_to']
vote_type = request.POST['vote_type']
return JsonResponse({'bool': cast_vote(vote_type, vote_to, user_id, id)})