Files
tech-blog/app/services/article_service.py
hz4th_coder e689fed71e 初始化技术博客项目
功能特性:
- 前端文章展示 (Markdown渲染、代码高亮)
- 后台管理系统 (文章、分类、标签、作者管理)
- 图片上传 (点击、拖拽、粘贴)
- 网站设置 (Logo、底部宣传图片上传)
- 访问统计 (IP记录、趋势图表)
- 参考来源、附件支持
- 单端口部署 (16012)

技术栈:
- Flask 3.0 + SQLAlchemy
- SQLite数据库
- marked.js + highlight.js (Markdown渲染)
- Chart.js (统计图表)
2026-06-04 23:12:34 +08:00

128 lines
4.1 KiB
Python

"""文章服务"""
from datetime import datetime
from slugify import slugify
from app import db
from app.models import Article, Category, Tag
class ArticleService:
"""文章业务逻辑"""
@staticmethod
def get_published_list(page=1, per_page=10, category_id=None, tag_id=None):
"""获取已发布文章列表"""
query = Article.query.filter_by(is_published=True)
if category_id:
query = query.filter_by(category_id=category_id)
if tag_id:
query = query.join(Article.tags).filter(Tag.id == tag_id)
return query.order_by(Article.published_at.desc()).paginate(
page=page, per_page=per_page, error_out=False
)
@staticmethod
def get_by_slug(slug):
"""通过slug获取文章"""
article = Article.query.filter_by(slug=slug, is_published=True).first()
if article:
# 增加浏览次数
article.view_count += 1
db.session.commit()
return article
@staticmethod
def get_by_id(article_id):
"""通过ID获取文章"""
return Article.query.get(article_id)
@staticmethod
def get_all_list(page=1, per_page=20, is_published=None):
"""获取所有文章列表(后台用)"""
query = Article.query
if is_published is not None:
query = query.filter_by(is_published=is_published)
return query.order_by(Article.updated_at.desc()).paginate(
page=page, per_page=per_page, error_out=False
)
@staticmethod
def create(title, content, summary=None, author_id=None, category_id=None, tag_ids=None,
cover_image=None, is_published=False):
"""创建文章"""
# 生成唯一slug
slug = slugify(title)
count = Article.query.filter(Article.slug.like(f'{slug}%')).count()
if count > 0:
slug = f'{slug}-{count + 1}'
article = Article(
title=title,
slug=slug,
content=content,
summary=summary or content[:200] + '...' if len(content) > 200 else content,
author_id=author_id,
category_id=category_id,
cover_image=cover_image,
is_published=is_published,
published_at=datetime.utcnow() if is_published else None
)
# 添加标签
if tag_ids:
tags = Tag.query.filter(Tag.id.in_(tag_ids)).all()
article.tags = tags
db.session.add(article)
db.session.commit()
return article
@staticmethod
def update(article_id, **kwargs):
"""更新文章"""
article = Article.query.get(article_id)
if not article:
return None
# 处理发布状态变化
if 'is_published' in kwargs and kwargs['is_published'] and not article.is_published:
kwargs['published_at'] = datetime.utcnow()
# 处理标签
tag_ids = kwargs.pop('tag_ids', None)
if tag_ids is not None:
tags = Tag.query.filter(Tag.id.in_(tag_ids)).all()
article.tags = tags
# 更新其他字段
for key, value in kwargs.items():
if hasattr(article, key):
setattr(article, key, value)
db.session.commit()
return article
@staticmethod
def delete(article_id):
"""删除文章"""
article = Article.query.get(article_id)
if article:
db.session.delete(article)
db.session.commit()
return True
return False
@staticmethod
def get_hot_articles(limit=5):
"""获取热门文章"""
return Article.query.filter_by(is_published=True)\
.order_by(Article.view_count.desc())\
.limit(limit).all()
@staticmethod
def get_recent_articles(limit=5):
"""获取最新文章"""
return Article.query.filter_by(is_published=True)\
.order_by(Article.published_at.desc())\
.limit(limit).all()