0

I am building a Q&A website as my first django project for practice (bad choice for a first project), however I created a question model(PoliticsPost) and an answer model(Answer) and I linked the answer model with the question model using a foreign key and the answer instances with the question instances using the ID of the question being answered. The logic of the website is that the questions are displayed in a template (list view), and each question is a link to its description (detail view) and all the answers associated with it (list view). The issue is that, although I inserted both the question context name and the answer context name in the template, the browser only renders the questions detail view.

(Sorry if this is confusing, it is because I am confused in the first place)

Here is the code:

views.py:

     class Home(ListView):
    model= PoliticsPost
    context_object_name = 'politicsposts'
    ordering = ['-date_posted']
    paginate_by = 5


def about(request):
    return render(request, 'lisk_templates/about_template.html')


@login_required
def interests(request):
    return render(request, 'lisk_templates/interests_template.html')


class Profile(LoginRequiredMixin,ListView):
    model = PoliticsPost
    context_object_name = 'politicsposts'
    paginate_by = 5
    ordering = ['-date_posted']


class Outerprofile(ListView):
    model = PoliticsPost
    context_object_name = 'politicsposts'
    paginate_by = 5

    def get_queryset(self):
        user = get_object_or_404(User, username=self.kwargs.get('username'))
        return PoliticsPost.objects.filter(author=user).order_by('-date_posted')


#POLITICS-------------


class Politics_topic(ListView):
    model= PoliticsPost
    context_object_name = 'politicsposts'
    ordering = ['-date_posted']
    paginate_by = 5


class Politics_post_details(DetailView):
    model = PoliticsPost
    context_object_name = 'politicsposts'



class Questionpolitics(LoginRequiredMixin, CreateView):
    model = PoliticsPost
    fields =['question','description']
    success_url = reverse_lazy('Politics_topic')

    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)


class Updatepolitics(LoginRequiredMixin,UserPassesTestMixin,UpdateView):
    model = PoliticsPost
    fields = ['question','description']
    success_url = reverse_lazy('Politics_topic')

    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)

    def test_func(self):
        post = self.get_object()
        if self.request.user == post.author:
            return True
        return False


class Deletepoliticspost(LoginRequiredMixin, UserPassesTestMixin, DeleteView):

    model = PoliticsPost
    success_url = reverse_lazy('Politics_topic')

    def test_func(self):
        post = self.get_object()
        if self.request.user == post.author:
            return True
        return False



#ANSWER


class CreateAnswer(LoginRequiredMixin,CreateView):
    model = Answer
    fields = ['content']
    success_url = reverse_lazy('Lisk home')
    question_id = 'qid'
    pk_url_kwarg = 'aid'



    def form_valid(self, form):
        try:
            question = PoliticsPost.objects.get(pk=self.kwargs[self.question_id])
        except PoliticsPost.DoesNotExist:
            form.add_error(None, 'Invalid question')
            return self.form_invalid(form)
        form.instance.post = question
        form.instance.author = self.request.user
        return super().form_valid(form)

class Answers(ListView):
    model = Answer
    context_object_name = 'answers'
    ordering = ['-date_posted']

    def get_queryset(self):
        question_id = get_object_or_404(PoliticsPost, pk=self.kwargs.get('qid'))
        return Answer.objects.filter(post_id=question_id)

urls.py(not root):

path('politicspost/<int:pk>/',views.Politics_post_details.as_view(template_name='lisk_templates/politics_post_details.html'),
             name='politics_post_details'),

urls.py(not root):     path('politicspost/<int:qid>',views.Answers.as_view(template_name='lisk_templates/politics_post_details.html'),name ='answerslist')

politics_post_template.html:

{%extends "lisk_templates/base.html"%}
{% block title %}
    Post Details
{% endblock title %}

{%block body%}
    <h1 id="page_topic">Page topic</h1>
    <div class="feed">
        <div class="question">

            <h1>{{ politicsposts.question }}</h1>
            <p><img src="{{ politicsposts.author.profile.image.url }}" height="30" width="30">
                <br>
                By <a href="{% url 'Outerprofile' politicsposts.author.username %}">{{ politicsposts.author }}</a> | <span>{{ politicsposts.date_posted }}</span></p>
            <h4>{{ politicsposts.description }}</h4>

            <hr>
             <a href="{% url 'Answer' politicsposts.id %}" class="speciallink">Answer</a>
              {%  if politicsposts.author == user %}
                <a href="{% url 'updatepoliticspost' politicsposts.id %}" class="speciallink" style="fontsize:14px;">Edit</a>
                <a href="{% url 'deletepoliticspost' politicsposts.id %}" class="speciallink">Delete</a>
            {% endif %}
            <hr>
            <h2>Answers:</h2>
            <hr>
            {% for answer in answers %}
                {% if answer.post == politicsposts %}
                    {{ answer.author }}{{ answer.content }}
                {% endif %}
            {% endfor %}
            </div>
      </div>
{% endblock body %}

models.py:

class PoliticsPost(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)
    #solution = models.TextField(null=True,blank=True)


    def __str__(self):
        return self.question

class Answer(models.Model):
    content = models.TextField(null=True,blank=True)
    post = models.ForeignKey(PoliticsPost, on_delete=models.CASCADE)
    author = models.ForeignKey(User,on_delete=models.CASCADE)
    date_posted = models.DateTimeField(default=timezone.now)
    post_id = post.pk

I know for sure that the answers are linked to a question because when I check the admin page I can see all the answers to a specific question.

Thanks in advance.

1 Answers1

1

You have two different urls referring to two different views, so you can't expect to see the information from two views in one template.

If I understand your setup correctly, you need to overwrite get_context_data for example in your Politics_post_details view in order to be able to access the related answers.

Something like this for example:

def get_context_data(self, **kwargs):
   context = super().get_context_data(**kwargs)
   # now you can get any additional information you want from other models
   question_id = get_object_or_404(PoliticsPost, pk=self.kwargs.get('qid'))
   context['answer'] = Answer.objects.filter(post_id=question_id)
   return context

And then you should be able to use {{answer}} in your template.

MeL
  • 1,269
  • 3
  • 12
  • 30
  • Thanks for the help man, I just wanted to let you know that post_id is a variable under the Answer model and is equal to post,primary_key, and wanted to know if the solution still stands. Thanks again. @MeL – Ahmed Mekky Jul 17 '20 at 01:43
  • 1
    If `post_id` is the field name on your `Answer` model, then yes, you can filter on that. You're welcome! – MeL Jul 17 '20 at 02:04
  • what is a field name, post_id is the id of the post(PoliticsPost) the answer is associated with – Ahmed Mekky Jul 17 '20 at 02:09
  • 1
    You will need to change your model setup, e.g. make `post_id` a `OnetoOneField`, you can't just say `post_id = post.pk`, that won't work – MeL Jul 17 '20 at 02:12
  • will this work ? `post_id = models.OneToOneField(post.primary_key,on_delete=models.PROTECT)` @MeL, sorry if I am being annoying, but you are my only hope man. – Ahmed Mekky Jul 17 '20 at 02:22
  • 1
    No, you have to use the model. i.e.: `post_id = models.OneToOneField(PoliticsPost,on_delete=models.PROTECT, primary_key=True)`. Also check out the documentation: https://docs.djangoproject.com/en/3.0/topics/db/examples/one_to_one/ – MeL Jul 17 '20 at 02:30
  • ,, so should I remove the politicspost foriegnkey under the Answer class after adding this ? or should I keep it ? – Ahmed Mekky Jul 17 '20 at 02:42
  • 1
    Oh I see now you already have it, just remove `post_id`, you don't need it. You need to decide for yourself whether `ForeignKey` or `OnetoOneField` is more appropriate in your case. For a discussion on this, see: https://stackoverflow.com/a/5891861/13290801 – MeL Jul 17 '20 at 03:02
  • I want a question to have more than one answer, so I will go with `ForeignKey` Thanks man. – Ahmed Mekky Jul 17 '20 at 03:31
  • It did not work, `{{ answer }}` still does not get rendered I added `def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # now you can get any additional information you want from other models question_id = get_object_or_404(PoliticsPost, pk=self.kwargs.get('qid')) context['answer'] = Answer.objects.filter(post=question_id) return context` to the `Politics_post_details` view and nothing changed. @MeL – Ahmed Mekky Jul 17 '20 at 04:27
  • Thank you it worked, I was sleepy yesterday and I did a typo, I owe you man. @MeL – Ahmed Mekky Jul 17 '20 at 14:50
  • I have one extra question, how can i delete the answers, I created a class based view (DeleteView) for the answers and set the url to be `path('politicspost//answer//delete/',views.AnswerDelete.as_view(template_name = 'lisk_templates/answer_delete.html'),name='Answer_Delete')` but the template does not appear. – Ahmed Mekky Jul 18 '20 at 03:52
  • thought it would be better to get the answer from someone who already knows the logic of this code, it is ok if you do not want to answer. – Ahmed Mekky Jul 18 '20 at 22:18
  • Write a new question with all the necessary code and explanation and post the link here, I will take a look – MeL Jul 18 '20 at 22:19
  • https://stackoverflow.com/questions/62964507/how-can-i-delete-the-answers-code-in-body/62964585#62964585 – Ahmed Mekky Jul 18 '20 at 22:52