Add tags on articles and list view
This commit is contained in:
parent
8d5edfd8df
commit
4ddf916364
6 changed files with 60 additions and 7 deletions
40
articles/migrations/0030_tag_slug.py
Normal file
40
articles/migrations/0030_tag_slug.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Generated by Django 3.1.5 on 2021-03-04 17:17
|
||||
|
||||
from django.db import migrations, models
|
||||
from django.utils.text import slugify
|
||||
|
||||
|
||||
def forwards(apps, schema_editor):
|
||||
Tag = apps.get_model("articles", "Tag")
|
||||
db_alias = schema_editor.connection.alias
|
||||
tags = Tag.objects.using(db_alias).all()
|
||||
for tag in tags:
|
||||
tag.slug = slugify(tag.name)
|
||||
Tag.objects.bulk_update(tags, ["slug"])
|
||||
|
||||
|
||||
def backwards(apps, schema_editor):
|
||||
Tag = apps.get_model("articles", "Tag")
|
||||
db_alias = schema_editor.connection.alias
|
||||
Tag.objects.using(db_alias).update(slug="")
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("articles", "0029_auto_20210303_1711"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="tag",
|
||||
name="slug",
|
||||
field=models.CharField(blank=True, max_length=255),
|
||||
),
|
||||
migrations.RunPython(forwards, backwards),
|
||||
migrations.AlterField(
|
||||
model_name="tag",
|
||||
name="slug",
|
||||
field=models.CharField(max_length=255, unique=True),
|
||||
),
|
||||
]
|
|
@ -25,6 +25,7 @@ class User(AbstractUser):
|
|||
|
||||
class Tag(models.Model):
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
slug = models.CharField(max_length=255, unique=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ["name"]
|
||||
|
|
|
@ -20,7 +20,7 @@ footer > :first-child {
|
|||
margin-top: 1em;
|
||||
}
|
||||
|
||||
nav a:not(:first-child):before {
|
||||
nav a:not(:first-child):before, a.tag:not(:first-of-type):before {
|
||||
content: '\00B7';
|
||||
margin: 0 5px;
|
||||
color: var(--nc-tx-1);
|
||||
|
|
|
@ -2,4 +2,7 @@
|
|||
Published on {% include "articles/snippets/datetime.html" %}
|
||||
· {{ article.get_read_time }} min read
|
||||
{% include "articles/snippets/admin_link.html" %}
|
||||
{% if article.tags.all %}
|
||||
<br>{% for tag in article.tags.all %}<a href="{% url "tag" slug=tag.slug %}" class="tag">{{ tag.name }}</a>{% endfor %}
|
||||
{% endif %}
|
||||
</p>
|
||||
|
|
|
@ -6,6 +6,7 @@ urlpatterns = [
|
|||
path("", html.ArticlesListView.as_view(), name="articles-list"),
|
||||
path("drafts/", html.DraftsListView.as_view(), name="drafts-list"),
|
||||
path("search/", html.SearchArticlesListView.as_view(), name="search"),
|
||||
path("tag/<slug:slug>/", html.TagArticlesListView.as_view(), name="tag"),
|
||||
path("feed/", feeds.CompleteFeed(), name="complete-feed"),
|
||||
path("api/render/<int:article_pk>/", api.render_article, name="api-render-article"),
|
||||
path("<slug:slug>/", html.ArticleDetailView.as_view(), name="article-detail"),
|
||||
|
|
|
@ -5,9 +5,10 @@ from typing import Dict
|
|||
from django.conf import settings
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.db.models import F, Q
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.views import generic
|
||||
|
||||
from articles.models import Article
|
||||
from articles.models import Article, Tag
|
||||
|
||||
|
||||
class BaseArticleListView(generic.ListView):
|
||||
|
@ -41,9 +42,11 @@ class BaseArticleListView(generic.ListView):
|
|||
return "&".join(map(lambda item: f"{item[0]}={item[1]}", querystring.items()))
|
||||
|
||||
|
||||
class ArticlesListView(BaseArticleListView):
|
||||
class PublicArticleListView(BaseArticleListView):
|
||||
queryset = Article.objects.filter(status=Article.PUBLISHED)
|
||||
|
||||
|
||||
class ArticlesListView(PublicArticleListView):
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
home_article = Article.objects.filter(
|
||||
|
@ -53,8 +56,7 @@ class ArticlesListView(BaseArticleListView):
|
|||
return context
|
||||
|
||||
|
||||
class SearchArticlesListView(BaseArticleListView):
|
||||
queryset = Article.objects.filter(status=Article.PUBLISHED)
|
||||
class SearchArticlesListView(PublicArticleListView):
|
||||
template_name = "articles/article_search.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
@ -85,6 +87,12 @@ class SearchArticlesListView(BaseArticleListView):
|
|||
return {}
|
||||
|
||||
|
||||
class TagArticlesListView(PublicArticleListView):
|
||||
def get_queryset(self):
|
||||
tag = get_object_or_404(Tag, slug=self.kwargs.get("slug"))
|
||||
return super().get_queryset().filter(tags=tag)
|
||||
|
||||
|
||||
class DraftsListView(LoginRequiredMixin, BaseArticleListView):
|
||||
queryset = Article.objects.filter(status=Article.DRAFT)
|
||||
|
||||
|
@ -103,9 +111,9 @@ class ArticleDetailView(generic.DetailView):
|
|||
def get_queryset(self):
|
||||
key = self.request.GET.get("draft_key")
|
||||
if key:
|
||||
return Article.objects.filter(draft_key=key)
|
||||
return Article.objects.filter(draft_key=key).prefetch_related("tags")
|
||||
|
||||
queryset = super().get_queryset()
|
||||
queryset = super().get_queryset().prefetch_related("tags")
|
||||
if not self.request.user.is_authenticated:
|
||||
queryset = queryset.filter(status=Article.PUBLISHED)
|
||||
return queryset
|
||||
|
|
Reference in a new issue