Refactor articles model
This commit is contained in:
parent
4b224f0a1f
commit
d59565fa82
3 changed files with 58 additions and 43 deletions
|
@ -1,10 +1,7 @@
|
||||||
import random
|
import random
|
||||||
import re
|
|
||||||
import uuid
|
import uuid
|
||||||
from functools import cached_property, reduce
|
from functools import cached_property, reduce
|
||||||
|
|
||||||
import html2text
|
|
||||||
import markdown
|
|
||||||
import readtime
|
import readtime
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
@ -12,39 +9,20 @@ from django.db import models
|
||||||
from django.template.defaultfilters import slugify
|
from django.template.defaultfilters import slugify
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from markdown.extensions.codehilite import CodeHiliteExtension
|
|
||||||
|
|
||||||
from articles.markdown import LazyLoadingImageExtension
|
from articles.utils import (
|
||||||
from articles.utils import build_full_absolute_url
|
build_full_absolute_url,
|
||||||
|
format_article_content,
|
||||||
|
get_html_to_text_converter,
|
||||||
|
truncate_words_after_char_count,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class User(AbstractUser):
|
class User(AbstractUser):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AdminUrlMixin:
|
class Article(models.Model):
|
||||||
def get_admin_url(self):
|
|
||||||
content_type = ContentType.objects.get_for_model(self.__class__)
|
|
||||||
return reverse(
|
|
||||||
"admin:%s_%s_change" % (content_type.app_label, content_type.model),
|
|
||||||
args=(self.id,),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def format_article_content(content):
|
|
||||||
md = markdown.Markdown(
|
|
||||||
extensions=[
|
|
||||||
"extra",
|
|
||||||
"admonition",
|
|
||||||
CodeHiliteExtension(linenums=False, guess_lang=False),
|
|
||||||
LazyLoadingImageExtension(),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
content = re.sub(r"(\s)#(\w+)", r"\1\#\2", content)
|
|
||||||
return md.convert(content)
|
|
||||||
|
|
||||||
|
|
||||||
class Article(AdminUrlMixin, models.Model):
|
|
||||||
DRAFT = "draft"
|
DRAFT = "draft"
|
||||||
PUBLISHED = "published"
|
PUBLISHED = "published"
|
||||||
STATUS_CHOICES = [
|
STATUS_CHOICES = [
|
||||||
|
@ -82,20 +60,9 @@ class Article(AdminUrlMixin, models.Model):
|
||||||
@cached_property
|
@cached_property
|
||||||
def get_description(self):
|
def get_description(self):
|
||||||
html = self.get_formatted_content
|
html = self.get_formatted_content
|
||||||
converter = html2text.HTML2Text()
|
converter = get_html_to_text_converter()
|
||||||
converter.ignore_images = True
|
|
||||||
converter.ignore_links = True
|
|
||||||
converter.ignore_tables = True
|
|
||||||
converter.ignore_emphasis = True
|
|
||||||
text = converter.handle(html)
|
text = converter.handle(html)
|
||||||
total_length = 0
|
return truncate_words_after_char_count(text, 160)
|
||||||
text_result = []
|
|
||||||
for word in text.split():
|
|
||||||
if len(word) + 1 + total_length > 160:
|
|
||||||
break
|
|
||||||
text_result.append(word)
|
|
||||||
total_length += len(word) + 1
|
|
||||||
return " ".join(text_result) + "..."
|
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def get_formatted_content(self):
|
def get_formatted_content(self):
|
||||||
|
@ -165,3 +132,10 @@ class Article(AdminUrlMixin, models.Model):
|
||||||
|
|
||||||
css = self.custom_css.replace("\n", " ")
|
css = self.custom_css.replace("\n", " ")
|
||||||
return reduce(reducer, css, "")
|
return reduce(reducer, css, "")
|
||||||
|
|
||||||
|
def get_admin_url(self):
|
||||||
|
content_type = ContentType.objects.get_for_model(self.__class__)
|
||||||
|
return reverse(
|
||||||
|
"admin:%s_%s_change" % (content_type.app_label, content_type.model),
|
||||||
|
args=(self.id,),
|
||||||
|
)
|
||||||
|
|
|
@ -2,7 +2,8 @@ import pytest
|
||||||
from django.test import Client
|
from django.test import Client
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from articles.models import Article, format_article_content
|
from articles.models import Article
|
||||||
|
from articles.utils import format_article_content
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
import html2text
|
||||||
|
import markdown
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from markdown.extensions.codehilite import CodeHiliteExtension
|
||||||
|
|
||||||
|
from articles.markdown import LazyLoadingImageExtension
|
||||||
|
|
||||||
|
|
||||||
def build_full_absolute_url(request, url):
|
def build_full_absolute_url(request, url):
|
||||||
|
@ -6,3 +13,36 @@ def build_full_absolute_url(request, url):
|
||||||
return request.build_absolute_uri(url)
|
return request.build_absolute_uri(url)
|
||||||
else:
|
else:
|
||||||
return (settings.BLOG["base_url"] + url)[::-1].replace("//", "/", 1)[::-1]
|
return (settings.BLOG["base_url"] + url)[::-1].replace("//", "/", 1)[::-1]
|
||||||
|
|
||||||
|
|
||||||
|
def format_article_content(content):
|
||||||
|
md = markdown.Markdown(
|
||||||
|
extensions=[
|
||||||
|
"extra",
|
||||||
|
"admonition",
|
||||||
|
CodeHiliteExtension(linenums=False, guess_lang=False),
|
||||||
|
LazyLoadingImageExtension(),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
content = re.sub(r"(\s)#(\w+)", r"\1\#\2", content)
|
||||||
|
return md.convert(content)
|
||||||
|
|
||||||
|
|
||||||
|
def truncate_words_after_char_count(text, char_count):
|
||||||
|
total_length = 0
|
||||||
|
text_result = []
|
||||||
|
for word in text.split():
|
||||||
|
if len(word) + 1 + total_length > char_count:
|
||||||
|
break
|
||||||
|
text_result.append(word)
|
||||||
|
total_length += len(word) + 1
|
||||||
|
return " ".join(text_result) + "..."
|
||||||
|
|
||||||
|
|
||||||
|
def get_html_to_text_converter():
|
||||||
|
converter = html2text.HTML2Text()
|
||||||
|
converter.ignore_images = True
|
||||||
|
converter.ignore_links = True
|
||||||
|
converter.ignore_tables = True
|
||||||
|
converter.ignore_emphasis = True
|
||||||
|
return converter
|
||||||
|
|
Reference in a new issue