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