Home > database >  Only able to get /article/1/ to load. /article/2/ displays a 404
Only able to get /article/1/ to load. /article/2/ displays a 404

Time:01-11

Each page in /articles/x/ represents one article, each article has its own article content which is in the ArticleContent model which is structure like

id tag css_id css_class content article_id (foreign key that points to Article Table)
1 p blab la 1
2 p bahaofs 2

actual database has more records for multiple article_ids

loading /article/1/ works exactly as expected with article content

ArticleContent Model

class ArticleContent(models.Model):

    article = models.ForeignKey('Article', on_delete=models.CASCADE)
    order = models.IntegerField(blank=True)
    tag = models.CharField(max_length=20)
    css_id = models.CharField(max_length=100, blank=True)
    css_class = models.CharField(max_length=100, blank=True)
    extra = models.TextField(max_length=200, blank=True)
    content = models.TextField(max_length=2000, blank=True)

Article Model

class Article(models.Model):

    def __str__(self) -> str:
        return self.title

    title = models.TextField(max_length=200)
    slug = models.SlugField(max_length=100, blank=True)
    preview = models.TextField(max_length=500)
    hasimage = models.BooleanField(default=True)
    image = models.ImageField(upload_to='articles/static/articles/images', blank=True)
    date = models.DateTimeField(blank=True)
    url = models.TextField(blank=True)
    alt = models.TextField(max_length=1000, blank=True)

urls.py

app_name = 'article'

urlpatterns = [
    path('', views.index, name='index'),
    path('articles/<int:pk>/', views.DetailView.as_view(), name='article_detail'),
]

views

class DetailView(generic.DetailView):
    
    model = ArticleContent
    template_name = 'articles/article_detail.html'

    def get_queryset(self, *args, **kwargs):
        article_content = ArticleContent.objects.filter(article_id=self.kwargs['pk'])
        return article_content

    def get_context_data(self, *args, **kwargs):
        # Call the base implementation first to get a context
        context = super().get_context_data(**kwargs)
        # Add in settings
        context['ordered_article_content'] = self.get_queryset()
        context['kwargs'] = self.kwargs['pk']
        context['is_header_on'] = True
        context['is_footer_on'] = True
        context['header_links'] = HeaderLinks.objects.all()
        context['footer_links'] = FooterLinks.objects.all()
        return context

article_detail.html template

{% extends "./base.html" %}

{% block content %}

    {% for x in ordered_article_content %}
        <{{ x.tag }} id="{{ x.css_id }}"  {{ x.extra }} >{{ x.content }}</{{ x.tag }}>

    {% endfor %}

    {{ kwargs }}

{% endblock %}

Error for article/2/ Page not found (404) No article content found matching the query

Accessing article_id = 2 works on the articles/1/ page, so I think the problem is something to do with article/2 /. I have no idea why, because I don't specifically reference a particular article_id anywhere I think. Wondering if this is something to do with how django does views that I'm just not understanding.

I'm just trying to get article/2 / to render the same way article/1/ does

CodePudding user response:

You should implement get_object: get_queryset is filtered additionally on the primary key in a DetailView, so:

from django.shortcuts import get_object_or_404

class DetailView(generic.DetailView):
    model = ArticleContent
    template_name = 'articles/article_detail.html'

    def get_object(self, *args, **kwargs):
        return get_object_or_404(ArticleContent, lemons_id=self.kwargs['pk'])

    def get_context_data(self, *args, **kwargs):
        # Call the base implementation first to get a context
        context = super().get_context_data(**kwargs)
        context['kwargs'] = self.kwargs['pk']
        context['is_header_on'] = True
        context['is_footer_on'] = True
        context['header_links'] = HeaderLinks.objects.all()
        context['footer_links'] = FooterLinks.objects.all()
        return context

The item will be passed to the template as object, so you render it without a for loop with:

<{{ object.tag }} id="{{ object.css_id }}"  {{ object.extra }} >{{ object.content }}</{{ object.tag }}>

But likely what you want is a ListView, so:

class MyListView(generic.ListView):
    model = ArticleContent
    template_name = 'articles/article_detail.html'
    context_object_name = 'ordered_article_content'

    def get_queryset(self, *args, **kwargs):
        article_content = ArticleContent.objects.filter(article_id=self.kwargs['pk'])
        return article_content

    def get_context_data(self, *args, **kwargs):
        # Call the base implementation first to get a context
        context = super().get_context_data(**kwargs)
        # Add in settings
        context['kwargs'] = self.kwargs['pk']
        context['is_header_on'] = True
        context['is_footer_on'] = True
        context['header_links'] = HeaderLinks.objects.all()
        context['footer_links'] = FooterLinks.objects.all()
        return context
  • Related