feat:更新数据模型定义
This commit is contained in:
@@ -1,100 +1,129 @@
|
|||||||
from sqlalchemy import (
|
from sqlalchemy import (BigInteger, Boolean, Column, Integer, DECIMAL, String, LargeBinary)
|
||||||
BigInteger,
|
|
||||||
Boolean,
|
|
||||||
Column,
|
|
||||||
Integer,
|
|
||||||
DECIMAL,
|
|
||||||
SMALLINT,
|
|
||||||
String,
|
|
||||||
LargeBinary
|
|
||||||
)
|
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
from models.base import AuditBase, IdBase
|
from models.base import AuditBase, IdBase
|
||||||
|
|
||||||
|
|
||||||
class Blog(AuditBase):
|
class Blog(AuditBase):
|
||||||
title = Column(String(255), nullable=True, comment="博客标题")
|
title = Column(String(255), nullable=False, comment="博客标题")
|
||||||
top_value = Column(Integer, nullable=True, comment="置顶值 越大越靠前")
|
top_value = Column(Integer, nullable=False, default=0, comment="置顶值 越大越靠前")
|
||||||
is_great = Column(Boolean, nullable=True, comment="是否是精品 0否1是")
|
is_great = Column(Boolean, nullable=False, default=False, comment="是否是精品")
|
||||||
category_id = Column(BigInteger, nullable=True, comment="博客类别")
|
category_id = Column(BigInteger, nullable=False, comment="博客类别")
|
||||||
summary = Column(String(255), nullable=True, comment="博客内容概要")
|
summary = Column(String(255), nullable=False, comment="博客内容概要")
|
||||||
content_id = Column(BigInteger, nullable=True, comment="博客内容")
|
content_id = Column(BigInteger, nullable=False, comment="博客内容")
|
||||||
word_count = Column(Integer, nullable=True, comment="字数统计")
|
word_count = Column(Integer, nullable=False, default=0, comment="字数统计")
|
||||||
read_duration = Column(DECIMAL(10, 2), nullable=True, comment="阅读时长")
|
read_duration = Column(DECIMAL(10, 2), nullable=False, default=0.00, comment="阅读时长")
|
||||||
is_approved = Column(SMALLINT, nullable=True, comment="是否发布")
|
is_approved = Column(Boolean, nullable=False, default=False, comment="是否发布")
|
||||||
|
|
||||||
|
# 分类关系(多对一)
|
||||||
category = relationship(
|
category = relationship(
|
||||||
"BlogCategory",
|
"BlogCategory",
|
||||||
|
# 与BlogCategory的blogs属性建立双向关系
|
||||||
back_populates="blogs",
|
back_populates="blogs",
|
||||||
|
# 只级联保存和合并操作,不级联删除(删除博客不应删除分类
|
||||||
|
cascade="save-update, merge",
|
||||||
|
# 明确指定连接条件
|
||||||
|
# 如果数据库设置了外键可以省略
|
||||||
primaryjoin="foreign(Blog.category_id) == BlogCategory.id"
|
primaryjoin="foreign(Blog.category_id) == BlogCategory.id"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 内容关系(一对一)
|
||||||
content = relationship(
|
content = relationship(
|
||||||
"BlogContent",
|
"BlogContent",
|
||||||
|
# 与BlogContent的blog属性建立双向关系
|
||||||
back_populates="blog",
|
back_populates="blog",
|
||||||
|
# 完全级联操作:保存、合并、刷新、删除等所有操作都会级联
|
||||||
|
cascade="all, delete-orphan",
|
||||||
|
# 设置为False表示一对一关系,返回单个对象而不是列表
|
||||||
|
uselist=False,
|
||||||
|
# 确保内容只有一个父博客,与delete-orphan配合使用
|
||||||
|
single_parent=True,
|
||||||
|
# 明确指定连接条件
|
||||||
primaryjoin="foreign(Blog.content_id) == BlogContent.id"
|
primaryjoin="foreign(Blog.content_id) == BlogContent.id"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 访问记录(一对多)
|
||||||
visits = relationship(
|
visits = relationship(
|
||||||
"BlogVisit",
|
"BlogVisit",
|
||||||
|
# 与BlogVisit的blog属性建立双向关系
|
||||||
back_populates="blog",
|
back_populates="blog",
|
||||||
|
# 完全级联操作:博客删除时自动删除所有访问记录
|
||||||
|
cascade="all, delete-orphan",
|
||||||
|
# 明确指定连接条件
|
||||||
primaryjoin="Blog.id == foreign(BlogVisit.blog_id)"
|
primaryjoin="Blog.id == foreign(BlogVisit.blog_id)"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 4. 评论(一对多)
|
||||||
comments = relationship(
|
comments = relationship(
|
||||||
"BlogComment",
|
"BlogComment",
|
||||||
|
# 与BlogComment的blog属性建立双向关系
|
||||||
back_populates="blog",
|
back_populates="blog",
|
||||||
|
# 完全级联操作:博客删除时自动删除所有评论
|
||||||
|
cascade="all, delete-orphan",
|
||||||
|
# 明确指定连接条件
|
||||||
primaryjoin="Blog.id == foreign(BlogComment.blog_id)"
|
primaryjoin="Blog.id == foreign(BlogComment.blog_id)"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BlogCategory(AuditBase):
|
class BlogCategory(AuditBase):
|
||||||
name = Column(String(45), nullable=True, comment="类别名称")
|
name = Column(String(45), nullable=False, comment="类别名称")
|
||||||
|
|
||||||
blogs = relationship(
|
blogs = relationship(
|
||||||
"Blog",
|
"Blog",
|
||||||
|
# 与Blog的category属性建立双向关系
|
||||||
back_populates="category",
|
back_populates="category",
|
||||||
|
# 完全级联操作:分类删除时自动删除所有关联的博客
|
||||||
|
# 警告:这会级联删除分类下的所有博客,包括博客的内容、访问记录和评论
|
||||||
|
cascade="all, delete-orphan",
|
||||||
|
# 明确指定连接条件
|
||||||
primaryjoin="BlogCategory.id == foreign(Blog.category_id)"
|
primaryjoin="BlogCategory.id == foreign(Blog.category_id)"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BlogContent(IdBase):
|
class BlogContent(IdBase):
|
||||||
content = Column(LargeBinary, comment="博客内容")
|
content = Column(LargeBinary, nullable=False, comment="博客内容")
|
||||||
|
|
||||||
blog = relationship(
|
blog = relationship(
|
||||||
"Blog",
|
"Blog",
|
||||||
|
# 与Blog的content属性建立双向关系
|
||||||
back_populates="content",
|
back_populates="content",
|
||||||
|
# 设置为False表示一对一关系
|
||||||
|
uselist=False,
|
||||||
|
# 明确指定连接条件
|
||||||
primaryjoin="BlogContent.id == foreign(Blog.content_id)"
|
primaryjoin="BlogContent.id == foreign(Blog.content_id)"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BlogVisit(AuditBase):
|
class BlogVisit(AuditBase):
|
||||||
ip = Column(String(255), nullable=True, comment="ip地址")
|
ip = Column(String(255), nullable=False, comment="IP地址")
|
||||||
os = Column(String(255), nullable=True, comment="操作系统")
|
os = Column(String(255), nullable=False, comment="操作系统")
|
||||||
browser = Column(String(255), nullable=True, comment="浏览器")
|
browser = Column(String(255), nullable=False, comment="浏览器")
|
||||||
uri = Column(String(255), nullable=True, comment="路径")
|
uri = Column(String(255), nullable=False, comment="路径")
|
||||||
blog_id = Column(BigInteger, nullable=True, comment="博客id")
|
blog_id = Column(BigInteger, nullable=True, comment="博客ID")
|
||||||
|
|
||||||
blog = relationship(
|
blog = relationship(
|
||||||
"Blog",
|
"Blog",
|
||||||
|
# 与Blog的visits属性建立双向关系
|
||||||
back_populates="visits",
|
back_populates="visits",
|
||||||
|
# 明确指定连接条件
|
||||||
primaryjoin="foreign(BlogVisit.blog_id) == Blog.id"
|
primaryjoin="foreign(BlogVisit.blog_id) == Blog.id"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BlogComment(AuditBase):
|
class BlogComment(AuditBase):
|
||||||
blog_id = Column(BigInteger, nullable=True, comment="博客id")
|
blog_id = Column(BigInteger, nullable=False, comment="博客ID")
|
||||||
parent_id = Column(BigInteger, nullable=True, comment="父评论id")
|
parent_id = Column(BigInteger, nullable=False, comment="父评论ID")
|
||||||
name = Column(String(255), nullable=True, comment="评论人昵称")
|
name = Column(String(255), nullable=False, comment="评论人昵称")
|
||||||
website = Column(String(255), nullable=True, comment="评论人网站")
|
website = Column(String(255), nullable=True, comment="评论人网站")
|
||||||
ip_address = Column(String(45), nullable=True, comment="评论人ip")
|
ip_address = Column(String(45), nullable=False, comment="评论人IP")
|
||||||
user_agent = Column(String(255), nullable=True, comment="评论人浏览器信息")
|
user_agent = Column(String(255), nullable=False, comment="评论人浏览器信息")
|
||||||
content = Column(String(512), nullable=True, comment="评论内容")
|
content = Column(String(255), nullable=False, comment="评论内容")
|
||||||
is_approved = Column(SMALLINT, nullable=True, comment="是否通过")
|
is_approved = Column(Boolean, nullable=False, default=False, comment="是否通过")
|
||||||
|
|
||||||
blog = relationship(
|
blog = relationship(
|
||||||
"Blog",
|
"Blog",
|
||||||
|
# 与Blog的comments属性建立双向关系
|
||||||
back_populates="comments",
|
back_populates="comments",
|
||||||
|
# 明确指定连接条件
|
||||||
primaryjoin="foreign(BlogComment.blog_id) == Blog.id"
|
primaryjoin="foreign(BlogComment.blog_id) == Blog.id"
|
||||||
)
|
)
|
||||||
|
|||||||
121
schemas/blog.py
121
schemas/blog.py
@@ -1,25 +1,42 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel, Field, field_validator
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
class BlogQuery(BaseModel):
|
class BlogQuery(BaseModel):
|
||||||
# 类别
|
"""博客查询参数"""
|
||||||
category: Optional[str] = None
|
category: Optional[str] = Field(None, description="分类名称")
|
||||||
# 标题
|
title: Optional[str] = Field(None, description="标题关键词")
|
||||||
title: Optional[str] = None
|
year: Optional[int] = Field(None, description="发布年份", ge=2000, le=datetime.now().year)
|
||||||
# 年份
|
|
||||||
year: Optional[int] = None
|
@field_validator('year')
|
||||||
|
def validate_year(cls, v):
|
||||||
|
if v is not None and v > datetime.now().year:
|
||||||
|
raise ValueError('年份不能超过当前年份')
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
class BlogBase(BaseModel):
|
class BlogBase(BaseModel):
|
||||||
title: str
|
"""博客基础模型"""
|
||||||
topValue: int
|
title: str = Field(..., min_length=1, max_length=255, description="博客标题")
|
||||||
isGreat: bool
|
top_value: int = Field(default=0, ge=0, description="置顶值,越大越靠前", alias="topValue")
|
||||||
category: str
|
is_great: bool = Field(default=False, description="是否是精品", alias="isGreat")
|
||||||
content: Optional[str] = None
|
category: str = Field(..., min_length=1, max_length=45, description="分类名称")
|
||||||
isApproved: int
|
content: Optional[str] = Field(None, description="博客内容")
|
||||||
|
is_approved: bool = Field(default=False, description="是否已发布", alias="isApproved")
|
||||||
|
|
||||||
|
@field_validator('title')
|
||||||
|
def title_not_empty(cls, v):
|
||||||
|
if not v or not v.strip():
|
||||||
|
raise ValueError('标题不能为空')
|
||||||
|
return v.strip()
|
||||||
|
|
||||||
|
@field_validator('category')
|
||||||
|
def category_not_empty(cls, v):
|
||||||
|
if not v or not v.strip():
|
||||||
|
raise ValueError('分类不能为空')
|
||||||
|
return v.strip()
|
||||||
|
|
||||||
|
|
||||||
class BlogCreate(BlogBase):
|
class BlogCreate(BlogBase):
|
||||||
@@ -31,16 +48,17 @@ class BlogUpdate(BlogBase):
|
|||||||
|
|
||||||
|
|
||||||
class BlogResponse(BlogBase):
|
class BlogResponse(BlogBase):
|
||||||
id: Optional[int] = None
|
id: int = Field(..., description="博客ID")
|
||||||
summary: Optional[str] = None
|
summary: Optional[str] = Field(None, description="内容摘要")
|
||||||
wordCount: Optional[int] = None
|
word_count: Optional[int] = Field(None, description="字数统计", alias="wordCount")
|
||||||
readDuration: Optional[float] = None
|
read_duration: Optional[float] = Field(None, description="阅读时长", alias="readDuration")
|
||||||
visitCount: Optional[int] = None
|
visit_count: Optional[int] = Field(0, description="访问次数", alias="visitCount")
|
||||||
createTime: Optional[datetime] = None
|
create_time: datetime = Field(..., description="创建时间", alias="createTime")
|
||||||
updateTime: Optional[datetime] = None
|
update_time: datetime = Field(..., description="更新时间", alias="updateTime")
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
from_attributes = True
|
from_attributes = True
|
||||||
|
populate_by_name = True
|
||||||
json_encoders = {
|
json_encoders = {
|
||||||
# 自定义 datetime 类型的序列化格式
|
# 自定义 datetime 类型的序列化格式
|
||||||
datetime: lambda dt: dt.strftime('%Y-%m-%d %H:%M:%S')
|
datetime: lambda dt: dt.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
@@ -48,65 +66,82 @@ class BlogResponse(BlogBase):
|
|||||||
|
|
||||||
|
|
||||||
class BlogCategoryResponse(BaseModel):
|
class BlogCategoryResponse(BaseModel):
|
||||||
name: str
|
name: str = Field(..., description="分类名称")
|
||||||
count: int
|
count: int = Field(..., description="博客数量")
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
from_attributes = True
|
from_attributes = True
|
||||||
|
populate_by_name = True
|
||||||
|
|
||||||
|
|
||||||
class BlogStatsResponse(BaseModel):
|
class BlogStatsResponse(BaseModel):
|
||||||
blogCount: int
|
blog_count: int = Field(..., description="博客总数", alias="blogCount")
|
||||||
categoryCount: int
|
category_count: int = Field(..., description="分类总数", alias="categoryCount")
|
||||||
wordCount: int
|
word_count: int = Field(..., description="总字数", alias="wordCount")
|
||||||
|
|
||||||
|
|
||||||
class BlogVisitResponse(BaseModel):
|
class BlogVisitResponse(BaseModel):
|
||||||
ip: str
|
ip: str = Field(..., description="IP地址")
|
||||||
os: str
|
os: str = Field(..., description="操作系统")
|
||||||
browser: str
|
browser: str = Field(..., description="浏览器")
|
||||||
uri: str
|
uri: str = Field(..., description="访问路径")
|
||||||
title: Optional[str] = None
|
title: str = Field(None, description="博客标题")
|
||||||
visitTime: datetime
|
visit_time: datetime = Field(..., description="访问时间", alias="visitTime")
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
from_attributes = True
|
from_attributes = True
|
||||||
|
populate_by_name = True
|
||||||
json_encoders = {
|
json_encoders = {
|
||||||
datetime: lambda dt: dt.strftime('%Y-%m-%d %H:%M:%S')
|
datetime: lambda dt: dt.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class BlogLatestResponse(BaseModel):
|
class BlogLatestResponse(BaseModel):
|
||||||
id: int
|
id: int = Field(..., description="博客ID")
|
||||||
title: str
|
title: str = Field(..., description="博客标题")
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
from_attributes = True
|
from_attributes = True
|
||||||
|
populate_by_name = True
|
||||||
|
|
||||||
|
|
||||||
class BlogAdjacentResponse(BaseModel):
|
class BlogAdjacentResponse(BaseModel):
|
||||||
id: int
|
id: int = Field(..., description="博客ID")
|
||||||
title: str
|
title: str = Field(..., description="博客标题")
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
from_attributes = True
|
from_attributes = True
|
||||||
|
populate_by_name = True
|
||||||
|
|
||||||
|
|
||||||
class BlogCommentCreate(BaseModel):
|
class BlogCommentCreate(BaseModel):
|
||||||
parentId: int
|
parent_id: int = Field(default=0, ge=0, description="父评论ID,0表示顶级评论", alias="parentId")
|
||||||
name: str
|
name: str = Field(..., min_length=1, max_length=50, description="评论人昵称")
|
||||||
website: Optional[str] = None
|
website: Optional[str] = Field(None, description="评论人网站")
|
||||||
content: str
|
content: str = Field(..., min_length=1, max_length=1000, description="评论内容")
|
||||||
|
|
||||||
|
@field_validator('name')
|
||||||
|
def name_not_empty(cls, v):
|
||||||
|
if not v or not v.strip():
|
||||||
|
raise ValueError('昵称不能为空')
|
||||||
|
return v.strip()
|
||||||
|
|
||||||
|
@field_validator('content')
|
||||||
|
def content_not_empty(cls, v):
|
||||||
|
if not v or not v.strip():
|
||||||
|
raise ValueError('评论内容不能为空')
|
||||||
|
return v.strip()
|
||||||
|
|
||||||
|
|
||||||
class BlogCommentResponse(BlogCommentCreate):
|
class BlogCommentResponse(BlogCommentCreate):
|
||||||
id: int
|
id: int = Field(..., description="评论ID")
|
||||||
ipAddress: str
|
ip_address: str = Field(..., description="IP地址", alias="ipAddress")
|
||||||
userAgent: str
|
user_agent: str = Field(..., description="浏览器信息", alias="userAgent")
|
||||||
createTime: datetime
|
create_time: datetime = Field(..., description="创建时间", alias="createTime")
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
from_attributes = True
|
from_attributes = True
|
||||||
|
populate_by_name = True
|
||||||
json_encoders = {
|
json_encoders = {
|
||||||
# 自定义 datetime 类型的序列化格式
|
# 自定义 datetime 类型的序列化格式
|
||||||
datetime: lambda dt: dt.strftime('%Y-%m-%d %H:%M:%S')
|
datetime: lambda dt: dt.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
from sqlalchemy import select, func, desc, and_, asc, delete, distinct
|
from sqlalchemy import select, func, desc, and_, asc
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from models.blog import Blog, BlogCategory, BlogVisit, BlogContent, BlogComment
|
from models.blog import Blog, BlogCategory, BlogVisit, BlogContent, BlogComment
|
||||||
@@ -22,16 +22,16 @@ def query_blog_by_page(db: Session, current_page: int = 1, page_size: int = 10,
|
|||||||
stmt = (select(
|
stmt = (select(
|
||||||
Blog.id,
|
Blog.id,
|
||||||
Blog.title,
|
Blog.title,
|
||||||
Blog.top_value.label("topValue"),
|
Blog.top_value,
|
||||||
Blog.is_great.label("isGreat"),
|
Blog.is_great,
|
||||||
BlogCategory.name.label("category"),
|
BlogCategory.name.label("category"),
|
||||||
Blog.summary,
|
Blog.summary,
|
||||||
Blog.word_count.label("wordCount"),
|
Blog.word_count,
|
||||||
Blog.read_duration.label("readDuration"),
|
Blog.read_duration,
|
||||||
func.count(BlogVisit.id).label("visitCount"),
|
func.count(BlogVisit.id).label("visitCount"),
|
||||||
Blog.is_approved.label("isApproved"),
|
Blog.is_approved,
|
||||||
Blog.create_time.label("createTime"),
|
Blog.create_time,
|
||||||
Blog.update_time.label("updateTime")
|
Blog.update_time
|
||||||
).outerjoin(BlogCategory, Blog.category_id == BlogCategory.id)
|
).outerjoin(BlogCategory, Blog.category_id == BlogCategory.id)
|
||||||
.outerjoin(BlogVisit, Blog.id == BlogVisit.blog_id)
|
.outerjoin(BlogVisit, Blog.id == BlogVisit.blog_id)
|
||||||
.group_by(Blog.id, BlogCategory.name)
|
.group_by(Blog.id, BlogCategory.name)
|
||||||
@@ -53,17 +53,17 @@ def get_query_blog_by_condition_stmt(blog_query: BlogQuery):
|
|||||||
stmt = (select(
|
stmt = (select(
|
||||||
Blog.id,
|
Blog.id,
|
||||||
Blog.title,
|
Blog.title,
|
||||||
Blog.top_value.label("topValue"),
|
Blog.top_value,
|
||||||
Blog.is_great.label("isGreat"),
|
Blog.is_great,
|
||||||
BlogCategory.name.label("category"),
|
BlogCategory.name.label("category"),
|
||||||
Blog.summary,
|
Blog.summary,
|
||||||
BlogContent.content.label("content"),
|
BlogContent.content,
|
||||||
Blog.word_count.label("wordCount"),
|
Blog.word_count,
|
||||||
Blog.read_duration.label("readDuration"),
|
Blog.read_duration,
|
||||||
func.count(BlogVisit.id).label("visitCount"),
|
func.count(BlogVisit.id).label("visitCount"),
|
||||||
Blog.is_approved.label("isApproved"),
|
Blog.is_approved,
|
||||||
Blog.create_time.label("createTime"),
|
Blog.create_time,
|
||||||
Blog.update_time.label("updateTime")
|
Blog.update_time
|
||||||
).where(Blog.is_approved == 1)
|
).where(Blog.is_approved == 1)
|
||||||
.outerjoin(BlogCategory, Blog.category_id == BlogCategory.id)
|
.outerjoin(BlogCategory, Blog.category_id == BlogCategory.id)
|
||||||
.outerjoin(BlogContent, Blog.content_id == BlogContent.id)
|
.outerjoin(BlogContent, Blog.content_id == BlogContent.id)
|
||||||
@@ -99,17 +99,17 @@ def query_unapproved_blog(db: Session) -> List[BlogResponse]:
|
|||||||
stmt = ((select(
|
stmt = ((select(
|
||||||
Blog.id,
|
Blog.id,
|
||||||
Blog.title,
|
Blog.title,
|
||||||
Blog.top_value.label("topValue"),
|
Blog.top_value,
|
||||||
Blog.is_great.label("isGreat"),
|
Blog.is_great,
|
||||||
BlogCategory.name.label("category"),
|
BlogCategory.name.label("category"),
|
||||||
Blog.summary,
|
Blog.summary,
|
||||||
BlogContent.content.label("content"),
|
BlogContent.content,
|
||||||
Blog.word_count.label("wordCount"),
|
Blog.word_count,
|
||||||
Blog.read_duration.label("readDuration"),
|
Blog.read_duration,
|
||||||
func.count(BlogVisit.id).label("visitCount"),
|
func.count(BlogVisit.id),
|
||||||
Blog.is_approved.label("isApproved"),
|
Blog.is_approved,
|
||||||
Blog.create_time.label("createTime"),
|
Blog.create_time,
|
||||||
Blog.update_time.label("updateTime")
|
Blog.update_time
|
||||||
).where(Blog.is_approved == 0)
|
).where(Blog.is_approved == 0)
|
||||||
.outerjoin(BlogCategory, Blog.category_id == BlogCategory.id)
|
.outerjoin(BlogCategory, Blog.category_id == BlogCategory.id)
|
||||||
.outerjoin(BlogContent, Blog.content_id == BlogContent.id))
|
.outerjoin(BlogContent, Blog.content_id == BlogContent.id))
|
||||||
@@ -126,19 +126,19 @@ def query_blog_by_id(db: Session, blog_id: int) -> BlogResponse:
|
|||||||
check_blog_exist(db, blog_id)
|
check_blog_exist(db, blog_id)
|
||||||
|
|
||||||
stmt = (select(
|
stmt = (select(
|
||||||
Blog.id.label("id"),
|
Blog.id,
|
||||||
Blog.title.label("title"),
|
Blog.title,
|
||||||
Blog.top_value.label("topValue"),
|
Blog.top_value,
|
||||||
Blog.is_great.label("isGreat"),
|
Blog.is_great,
|
||||||
BlogCategory.name.label("category"),
|
BlogCategory.name.label("category"),
|
||||||
Blog.summary.label("summary"),
|
Blog.summary,
|
||||||
BlogContent.content.label("content"),
|
BlogContent.content,
|
||||||
Blog.word_count.label("wordCount"),
|
Blog.word_count,
|
||||||
Blog.read_duration.label("readDuration"),
|
Blog.read_duration,
|
||||||
func.count(BlogVisit.id).label("visitCount"),
|
func.count(BlogVisit.id).label("visitCount"),
|
||||||
Blog.is_approved.label("isApproved"),
|
Blog.is_approved,
|
||||||
Blog.create_time.label("createTime"),
|
Blog.create_time,
|
||||||
Blog.update_time.label("updateTime")
|
Blog.update_time
|
||||||
).where(Blog.id == blog_id)
|
).where(Blog.id == blog_id)
|
||||||
.outerjoin(BlogCategory, Blog.category_id == BlogCategory.id)
|
.outerjoin(BlogCategory, Blog.category_id == BlogCategory.id)
|
||||||
.outerjoin(BlogContent, Blog.content_id == BlogContent.id)
|
.outerjoin(BlogContent, Blog.content_id == BlogContent.id)
|
||||||
@@ -146,7 +146,7 @@ def query_blog_by_id(db: Session, blog_id: int) -> BlogResponse:
|
|||||||
|
|
||||||
blog = db.execute(stmt).first()
|
blog = db.execute(stmt).first()
|
||||||
|
|
||||||
return BlogResponse.from_orm(blog)
|
return BlogResponse.model_validate(blog)
|
||||||
|
|
||||||
|
|
||||||
def add_blog(db: Session, blog: BlogCreate) -> bool:
|
def add_blog(db: Session, blog: BlogCreate) -> bool:
|
||||||
@@ -154,16 +154,18 @@ def add_blog(db: Session, blog: BlogCreate) -> bool:
|
|||||||
|
|
||||||
db_blog = Blog(
|
db_blog = Blog(
|
||||||
title=blog.title,
|
title=blog.title,
|
||||||
top_value=blog.topValue,
|
top_value=blog.top_value,
|
||||||
is_great=blog.isGreat,
|
is_great=blog.is_great,
|
||||||
category_id=add_blog_category(db, blog.category),
|
category_id=add_blog_category(db, blog.category),
|
||||||
content_id=add_blog_content(db, blog.content),
|
|
||||||
summary=get_blog_summary(blog.content),
|
summary=get_blog_summary(blog.content),
|
||||||
word_count=word_count,
|
word_count=word_count,
|
||||||
read_duration=get_read_duration(word_count),
|
read_duration=get_read_duration(word_count),
|
||||||
is_approved=blog.isApproved
|
is_approved=blog.is_approved
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 级联新增
|
||||||
|
db_blog.content = BlogContent(content=blog.content.encode('utf-8'))
|
||||||
|
|
||||||
db.add(db_blog)
|
db.add(db_blog)
|
||||||
db.commit()
|
db.commit()
|
||||||
db.refresh(db_blog)
|
db.refresh(db_blog)
|
||||||
@@ -194,26 +196,17 @@ def add_blog_category(db: Session, category: str) -> int:
|
|||||||
return category_id
|
return category_id
|
||||||
|
|
||||||
|
|
||||||
def add_blog_content(db: Session, content: str) -> int:
|
|
||||||
db_blog_content = BlogContent(content=content.encode('utf-8'))
|
|
||||||
db.add(db_blog_content)
|
|
||||||
db.commit()
|
|
||||||
|
|
||||||
return db_blog_content.id
|
|
||||||
|
|
||||||
|
|
||||||
def update_blog(db: Session, blog_id: int, blog: BlogUpdate) -> bool:
|
def update_blog(db: Session, blog_id: int, blog: BlogUpdate) -> bool:
|
||||||
db_blog = check_blog_exist(db, blog_id)
|
db_blog = check_blog_exist(db, blog_id)
|
||||||
|
|
||||||
update_data = blog.model_dump(exclude_unset=True)
|
db_blog.title = blog.title
|
||||||
|
db_blog.top_value = blog.topValue
|
||||||
update_blog_content(db, db_blog.content_id, blog.content)
|
db_blog.is_great = blog.isGreat
|
||||||
|
|
||||||
db_blog.title = update_data["title"]
|
|
||||||
db_blog.top_value = update_data["topValue"]
|
|
||||||
db_blog.is_great = update_data["isGreat"]
|
|
||||||
db_blog.category_id = update_blog_category(db, blog.category)
|
db_blog.category_id = update_blog_category(db, blog.category)
|
||||||
|
|
||||||
|
# 级联更新
|
||||||
|
db_blog.content = BlogContent(content=blog.content.encode('utf-8'))
|
||||||
|
|
||||||
word_count = get_word_count(blog.content)
|
word_count = get_word_count(blog.content)
|
||||||
db_blog.summary = get_blog_summary(blog.content),
|
db_blog.summary = get_blog_summary(blog.content),
|
||||||
db_blog.word_count = word_count
|
db_blog.word_count = word_count
|
||||||
@@ -235,30 +228,11 @@ def update_blog_category(db: Session, category: str) -> int:
|
|||||||
return db_blog_category.id
|
return db_blog_category.id
|
||||||
|
|
||||||
|
|
||||||
def update_blog_content(db: Session, blog_content_id: int, blog_content: str) -> bool:
|
|
||||||
db_blog_content = check_blog_content_exist(db, blog_content_id)
|
|
||||||
|
|
||||||
db_blog_content.content = blog_content.encode('utf-8')
|
|
||||||
db.commit()
|
|
||||||
db.refresh(db_blog_content)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def delete_blog(db: Session, blog_id: int) -> bool:
|
def delete_blog(db: Session, blog_id: int) -> bool:
|
||||||
db_blog = check_blog_exist(db, blog_id)
|
db_blog = check_blog_exist(db, blog_id)
|
||||||
|
|
||||||
delete_blog_content(db, db_blog.content_id)
|
# 级联删除
|
||||||
db.execute(delete(Blog).where(Blog.id == blog_id))
|
db.delete(db_blog)
|
||||||
db.commit()
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def delete_blog_content(db: Session, blog_content_id: int) -> bool:
|
|
||||||
check_blog_content_exist(db, blog_content_id)
|
|
||||||
|
|
||||||
db.execute(delete(BlogContent).where(BlogContent.id == blog_content_id))
|
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -341,15 +315,15 @@ def query_blog_visit(db: Session, current_page: int = 1, page_size: int = 10) ->
|
|||||||
def query_blog_comment(db: Session, blog_id: int) -> List[BlogCommentResponse]:
|
def query_blog_comment(db: Session, blog_id: int) -> List[BlogCommentResponse]:
|
||||||
stmt = select(
|
stmt = select(
|
||||||
BlogComment.id,
|
BlogComment.id,
|
||||||
BlogComment.blog_id.label("blogId"),
|
BlogComment.blog_id,
|
||||||
BlogComment.parent_id.label("parentId"),
|
BlogComment.parent_id,
|
||||||
BlogComment.name,
|
BlogComment.name,
|
||||||
BlogComment.website,
|
BlogComment.website,
|
||||||
BlogComment.ip_address.label("ipAddress"),
|
BlogComment.ip_address,
|
||||||
BlogComment.user_agent.label("userAgent"),
|
BlogComment.user_agent,
|
||||||
BlogComment.content,
|
BlogComment.content,
|
||||||
BlogComment.is_approved.label("isApproved"),
|
BlogComment.is_approved,
|
||||||
BlogComment.create_time.label("createTime")
|
BlogComment.create_time
|
||||||
).where(BlogComment.blog_id == blog_id, BlogComment.is_approved == 1).order_by(desc(BlogComment.create_time))
|
).where(BlogComment.blog_id == blog_id, BlogComment.is_approved == 1).order_by(desc(BlogComment.create_time))
|
||||||
results = db.execute(stmt).fetchall()
|
results = db.execute(stmt).fetchall()
|
||||||
|
|
||||||
@@ -377,7 +351,7 @@ def add_blog_comment(db: Session, request: Request, blog_id: int, blog_comment:
|
|||||||
content=blog_comment.content,
|
content=blog_comment.content,
|
||||||
ip_address=request.client.host,
|
ip_address=request.client.host,
|
||||||
user_agent=request.headers.get("user-agent"),
|
user_agent=request.headers.get("user-agent"),
|
||||||
is_approved=1
|
is_approved=True
|
||||||
)
|
)
|
||||||
|
|
||||||
db.add(db_comment)
|
db.add(db_comment)
|
||||||
|
|||||||
Reference in New Issue
Block a user