Replace keywords by a Tag model

This commit is contained in:
Gabriel Augendre 2021-03-03 17:30:38 +01:00
parent 5722903301
commit 26cc694008
6 changed files with 123 additions and 20 deletions

View file

@ -1,11 +1,9 @@
import copy
from django.contrib import admin, messages
from django.contrib.admin import register
from django.contrib.auth.admin import UserAdmin
from django.shortcuts import redirect
from .models import Article, User
from .models import Article, Tag, User
admin.site.register(User, UserAdmin)
@ -40,7 +38,7 @@ class ArticleAdmin(admin.ModelAdmin):
{
"fields": [
("title", "slug"),
("author", "keywords"),
("author", "tags"),
("status", "published_at"),
("created_at", "updated_at"),
("views_count", "read_time"),
@ -71,7 +69,8 @@ class ArticleAdmin(admin.ModelAdmin):
]
prepopulated_fields = {"slug": ("title",)}
change_form_template = "articles/article_change_form.html"
search_fields = ["title", "content"]
search_fields = ["title", "content", "tags__name"]
autocomplete_fields = ["tags"]
def publish(self, request, queryset):
if not request.user.has_perm("articles.change_article"):
@ -133,3 +132,9 @@ class ArticleAdmin(admin.ModelAdmin):
return bool(instance.custom_css)
has_custom_css.boolean = True
@register(Tag)
class TagAdmin(admin.ModelAdmin):
list_display = ["name"]
search_fields = ["name"]

View file

@ -0,0 +1,62 @@
# Generated by Django 3.1.5 on 2021-03-03 15:33
from django.db import migrations, models
def forwards(apps, schema_editor):
Tag = apps.get_model("articles", "Tag")
Article = apps.get_model("articles", "Article")
db_alias = schema_editor.connection.alias
articles = Article.objects.using(db_alias).all()
for article in articles:
tags = []
for keyword in list(
filter(None, map(lambda k: k.strip(), article.keywords.split(",")))
):
tag = Tag.objects.using(db_alias).filter(name__iexact=keyword).first()
if tag is None:
tag = Tag.objects.create(name=keyword)
tags.append(tag)
article.tags.set(tags)
article.keywords = ""
Article.objects.bulk_update(articles, ["keywords"])
def backwards(apps, schema_editor):
Article = apps.get_model("articles", "Article")
db_alias = schema_editor.connection.alias
articles = Article.objects.using(db_alias).all()
for article in articles:
article.keywords = ",".join(map(lambda tag: tag.name, article.tags.all()))
Article.objects.bulk_update(articles, ["keywords"])
class Migration(migrations.Migration):
dependencies = [
("articles", "0026_article_draft_key"),
]
operations = [
migrations.CreateModel(
name="Tag",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=255, unique=True)),
],
),
migrations.AddField(
model_name="article",
name="tags",
field=models.ManyToManyField(related_name="articles", to="articles.Tag"),
),
migrations.RunPython(forwards, backwards),
]

View file

@ -0,0 +1,17 @@
# Generated by Django 3.1.5 on 2021-03-03 15:52
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("articles", "0027_auto_20210303_1633"),
]
operations = [
migrations.RemoveField(
model_name="article",
name="keywords",
),
]

View file

@ -0,0 +1,17 @@
# Generated by Django 3.1.5 on 2021-03-03 16:11
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("articles", "0028_remove_article_keywords"),
]
operations = [
migrations.AlterModelOptions(
name="tag",
options={"ordering": ["name"]},
),
]

View file

@ -23,6 +23,16 @@ class User(AbstractUser):
pass
class Tag(models.Model):
name = models.CharField(max_length=255, unique=True)
class Meta:
ordering = ["name"]
def __str__(self):
return self.name
class Article(models.Model):
DRAFT = "draft"
PUBLISHED = "published"
@ -39,11 +49,11 @@ class Article(models.Model):
author = models.ForeignKey(User, on_delete=models.PROTECT, default=1)
views_count = models.IntegerField(default=0)
slug = models.SlugField(unique=True, max_length=255)
keywords = models.CharField(max_length=255, blank=True)
has_code = models.BooleanField(default=False, blank=True)
is_home = models.BooleanField(default=False, blank=True)
custom_css = models.TextField(blank=True)
draft_key = models.UUIDField(default=uuid.uuid4)
tags = models.ManyToManyField(to=Tag, related_name="articles")
class Meta:
ordering = ["-published_at"]
@ -105,22 +115,14 @@ class Article(models.Model):
@cached_property
def get_related_articles(self):
related_articles = set()
for keyword in self.get_formatted_keywords:
potential_articles = Article.objects.filter(
keywords__icontains=keyword,
status=Article.PUBLISHED,
).exclude(pk=self.pk)
for article in potential_articles:
if keyword in article.get_formatted_keywords:
related_articles.add(article)
for tag in self.tags.all():
related_articles.update(tag.articles.all())
sample_size = min([len(related_articles), 3])
return random.sample(related_articles, sample_size)
@cached_property
def get_formatted_keywords(self):
return list(
filter(None, map(lambda k: k.strip().lower(), self.keywords.split(",")))
)
def keywords(self):
return ", ".join(map(lambda tag: tag.name, self.tags.all()))
@cached_property
def get_minified_custom_css(self):

View file

@ -74,9 +74,9 @@ class SearchArticlesListView(BaseArticleListView):
operator.and_, (Q(content__icontains=term) for term in search_terms)
)
| reduce(
operator.and_, (Q(keywords__icontains=term) for term in search_terms)
operator.and_, (Q(tags__name__icontains=term) for term in search_terms)
)
)
).distinct()
def get_additional_querystring_params(self) -> Dict[str, str]:
search_expression = self.request.GET.get("s")