How to set the question that an answer will be associated with?

I an building a Q&A website for practice and I want each answer to be associated with an author and a question, I managed to associate it with the user but I can not figure out the question part.

Here is the code:

models.py:

class Questiont(models.Model):     question = models.CharField(max_length=200)     description = models.TextField(null = True , blank=True)     date_posted =models.DateTimeField(default=timezone.now)     author = models.ForeignKey(User,on_delete=models.CASCADE)      def __str__(self):         return self.question  class Answer(models.Model):     content = models.TextField(null=True,blank=True)     question = models.ForeignKey(Question, on_delete=models.CASCADE)     author = models.ForeignKey(User,on_delete=models.CASCADE)     date_posted = models.DateTimeField(default=timezone.now) 

views.py(where the association should take place):

class CreateAnswer(LoginRequiredMixin,CreateView):     model = Answer     fields = ['content']     context_object_name = 'answer'     success_url = reverse_lazy('Lisk home')       def form_valid(self, form):         form.instance.question = ?????????         form.instance.author = self.request.user         return super().form_valid(form) 

How can I specify the question(form.instance.question) that the answer is specified to ? Granted that the ID of the question being answered is in the URL of the answering page(template).

The url is like this:

http://127.0.0.1:8000/question/22/createanswer/ 

urls.py(not root):

politicspost=questioon (sorry if this is messy)   path('politics_topic/', views.Politics_topic.as_view(template_name='lisk_templates/politics_topic_template.html'),          name='Politics_topic'),     path('ask_politics/', views.Questionpolitics.as_view(template_name='lisk_templates/ask_politics_template.html'),          name='ask_politics'),     path('politicspost/<int:pk>/',views.Politics_post_details.as_view(template_name='lisk_templates/politics_post_details.html'),          name='politics_post_details'),     path('politicspost/<int:pk>/update/',views.Updatepolitics.as_view(template_name='lisk_templates/ask_politics_template.html'),          name='updatepoliticspost'),     path('politicspost/<int:pk>/delete/',views.Deletepoliticspost.as_view(template_name='lisk_templates/delete_politics_confirmation.html'),name ='deletepoliticspost'),      #ANSWER     path('politicspost/<int:id>/createanswer/',views.CreateAnswer.as_view(template_name='lisk_templates/createanswer.html'),name = 'createanswer'),     path('answers/',views.Answerslist.as_view(template_name='lisk_templates/politics_post_details.html'),name ='answers') 

Thanks in advance.

Add Comment
2 Answer(s)

When you’re dealing with multiple objects in one view / url path, it’s always convenient to use descriptive names: use question_id not id, so that it differs from answer_id, which you may need later on: /politics_post/<int:question_id>/answers/<int:answer_id>/change/ for example.

These names are just labels. They are saved in the kwargs attribute of the CreateView. So /politics_post/42/answers/59/change will create: CreateView.kwargs = {'question_id': 42, 'answer_id': 59}. More information in the docs.

As @crimsonpython24 says, you can do this from a question perspective, but it’s equally fine to use Answer as your model. Now, I’m going to assume that you changed the url to have a question_id. You would change your create view like this:

class CreateAnswer(LoginRequiredMixin,CreateView):     model = Answer     fields = ['content']     context_object_name = 'answer'     success_url = reverse_lazy('Lisk home')     question_kwarg = 'question_id'       def form_valid(self, form):         try:             question = Question.objects.get(pk=self.kwargs[self.question_kwarg])         except Question.DoesNotExist:             form.add_error(None, 'Invalid question')             return self.form_invalid(form)         form.instance.question = question         form.instance.author = self.request.user         return super().form_valid(form) 
Add Comment

Seeing that you are already using a class-based view, I will suggest using the built-in UpdateView. In that way, you don’t have to do the extra handlings as you will be required to enter the primary key of the question in the URL (which the answers are going to be a part of) and Django will fetch the corresponding question itself.

Although, to me, your view name is misleading. Yes, you are creating an answer, but you are also updating the parent question object, and I believe that led you to choose Createview over Updateview – which the second one will be more favorable.

Basically, you will be adding an answer, but it’s more convenient to have it handled under a question object.

Add Comment

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.