张昊 4 months ago
parent b0041086be
commit a1f615f8fe

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.12" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12" project-jdk-type="Python SDK" />
</project>

@ -2,7 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/woniubiji.iml" filepath="$PROJECT_DIR$/.idea/woniubiji.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/woniu2.iml" filepath="$PROJECT_DIR$/.idea/woniu2.iml" />
</modules>
</component>
</project>

@ -5,7 +5,4 @@
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="renderExternalDocumentation" value="true" />
</component>
</module>

@ -0,0 +1,22 @@
# app.py
from main import app
from controller.index import index as index_blueprint
from controller.user import user as user_blueprint
from controller.article import article as article_blueprint
from controller.favorite import favorite as favorite_blueprint
from controller.comment import comment as comment_blueprint
from controller.admin import admin as admin_blueprint
from controller.ucenter import ucenter as ucenter_blueprint
from controller.ueditor import ueditor as ueditor_blueprint
#
app.register_blueprint(index_blueprint)
app.register_blueprint(user_blueprint)
app.register_blueprint(article_blueprint)
app.register_blueprint(favorite_blueprint)
app.register_blueprint(comment_blueprint)
app.register_blueprint(admin_blueprint)
app.register_blueprint(ucenter_blueprint)
app.register_blueprint(ueditor_blueprint)
if __name__ == '__main__':
app.run(debug=True)

@ -109,8 +109,8 @@ def send_email(receiver, ecode):
def gen_email_code():
return ''.join(random.choices(string.ascii_letters + string.digits, k=6))
# 测试邮箱能否发送成功
#
# # 测试邮箱能否发送成功
# code = gen_email_code()
# print(code)
# send_email('2082813839@qq.com', code)
@ -228,5 +228,3 @@ def generate_thumb(url_list):
# thumb = generate_thumb(list)
#
# print(thumb)

@ -0,0 +1,106 @@
from flask import Blueprint, render_template, session, request, jsonify
from module.article import Article
from module.user import Users
import math
admin = Blueprint("admin", __name__)
# @admin.before_request
# def before_admin():
# if session.get('islogin') != 'true' or session.get('role') != 'admin':
# return 'perm-denied'
# 为系统管理首页填充文章列表,并绘制分页栏
@admin.route('/admin')
def sys_admin():
pagesize = 50
article = Article()
result = article.find_all_except_draft(0, pagesize)
total = math.ceil(article.get_count_except_draft() / pagesize)
return render_template('system-admin.html', page=1, result=result, total=total)
@admin.route('/admin/user')
def sys_admin_user():
pagesize = 50
user = Users()
result = user.find_all_users()
total = math.ceil(user.get_total_count_user() / pagesize)
return render_template('system-admin-user.html', page=1, result=result, total=total)
# 为系统管理首页的文章列表进行分页查询
@admin.route('/admin/article/<int:page>')
def admin_article(page):
pagesize = 50
start = (page - 1) * pagesize
article = Article()
result = article.find_all_except_draft(start, pagesize)
total = math.ceil(article.get_count_except_draft() / pagesize)
return render_template('system-admin.html', page=page, result=result, total=total)
# 按照文章标题进行模糊查询的后台接口
@admin.route('/admin/search/<keyword>')
def admin_search_headline(keyword):
result = Article().find_by_headline_except_draft(keyword)
return render_template('system-admin.html', page=1, result=result, total=1)
# 文章的隐藏切换接口
@admin.route('/admin/article/hide/<int:articleid>')
def admin_article_hide(articleid):
print("articleid=",articleid)
hidden = Article().switch_hidden(articleid)
print("hidden=",hidden)
return str(hidden)
# 文章的推荐切换接口
@admin.route('/admin/article/recommend/<int:articleid>')
def admin_article_recommend(articleid):
recommended = Article().switch_recommended(articleid)
return str(recommended)
# 文章的审核切换接口
@admin.route('/admin/article/check/<int:articleid>')
def admin_article_check(articleid):
checked = Article().switch_checked(articleid)
return str(checked)
# 人员身份切换接口
@admin.route('/admin/user/role/<int:userid>')
def admin_user_check(userid):
role = Users().switch_role(userid)
return str(role)
# 删除文章
@admin.route('/admin/article/delete/<int:articleid>', methods=['GET'])
def delete_article(articleid):
article = Article()
try:
# 查找文章
result = article.find_by_id(articleid)
if result is None:
return jsonify({"success": False, "message": "文章不存在"})
# 删除文章
article.do_deletesign(articleid)
return jsonify({"success": True, "message": "删除成功"})
except Exception as e:
return jsonify({"success": False, "message": str(e)})
# 删除人员
@admin.route('/admin/user/delete/<int:userid>', methods=['GET'])
def delete_user(userid):
user = Users()
try:
# 查找人员
result = user.find_user_by_id(userid)
if result is None:
return jsonify({"success": False, "message": "用户不存在"})
# 删除人员
user.do_deletesign_user(userid)
return jsonify({"success": True, "message": "删除成功"})
except Exception as e:
return jsonify({"success": False, "message": str(e)})

@ -1,8 +1,11 @@
from flask import Blueprint, abort, render_template, request
from flask import Blueprint, abort, render_template, request, session
from module.article import Article
from module.comment import Comment
from module.credit import Credit
from module.thumb import Thumb
from module.user import Users
from bs4 import BeautifulSoup
from module.favorite import Favorite
article = Blueprint("article",__name__)
@ -21,19 +24,31 @@ def read(articleid):
content_half = ''.join([str(p) for p in soup.find_all('p')[:half_point]])
# 你可以在这里处理结果_last和result_next但注意边界条件
result_last = Article().find_by_id(articleid - 1) if articleid > 1 else None
result_next = Article().find_by_id(articleid + 1)
# result_last = Article().find_by_id(articleid - 1) if articleid > 1 else None
result_last = Article().find_max_less_than_id(articleid)
result_next = Article().find_min_greater_than_id(articleid)
# 每阅读一次,阅读次数加一
Article().update_readcount(articleid)
payed = Credit().check_payed_article(article)
# 是否看过
payed = Credit().check_payed_article(articleid) # 如果看过返回TRUE
# 是否收藏
is_favorited = Favorite().is_at_favorite(articleid)
# 传递评论的信息 这里的comment是指这一篇文章的所有的评论
comment = Comment().find_comment_with_user(articleid=articleid)
return render_template('article-user.html',
result=result,
result_content=content_half, # 传递前半部分的内容
result_last=result_last,
result_next=result_next,
position = half_point,
payed = payed)
payed = payed,
is_favorited = is_favorited,
comment = comment)
except:
abort(500)
@ -54,3 +69,8 @@ def read_all():
Users().update_credit((-1)*result.credit)
return content_half

@ -0,0 +1,125 @@
from flask import Blueprint, abort, render_template, request, session, jsonify
from module.comment import Comment
from module.credit import Credit
from module.article import Article
from module.thumb import Thumb
from module.user import Users
comment = Blueprint("comment",__name__)
@comment.route('/comment',methods = ['POST'])
def add_comment():
articleid = request.form.get('articleid')
content = request.form.get('content')
userid = session.get('userid')
ipaddr = request.remote_addr # 直接获取ip地址
# 对得到的comment进行校验这里只进行最简单的字数校验
if len(content) < 5 or len(content) > 1000:
return 'content-invalid'
# 校验结束,进行各种操作
try:
# 更新积分详情表 积分变化原因category 1评论comment 2注册enroll 3登录login 4投稿submission 5文章阅读read
Credit().insert_detail(category='1', target=userid, credit=2)
# 更新个人积分
Users().update_credit(2)
# 评论数量增加
Article().replaycount_add(articleid)
Comment().add_comment(articleid=articleid,content=content,ipaddr=ipaddr)
return 'add-pass'
except:
return 'add-fail'
# 评论点赞
@comment.route('/upcomment',methods = ['post'])
def up_comment():
commentid = request.form.get('commentid') # 通过post从前端页面那边拿取数据
articleid = request.form.get('articleid')
if session.get('islogin') is None: # 如果没有登录
return 'not-login'
else:
try:
Comment().update_add_agreecount(commentid=commentid)
Thumb().insert_up_detail(articleid=articleid,commentid=commentid)
return 'up-pass'
except:
return 'up-fail'
# 评论取消点赞
@comment.route('/cancelup',methods = ['post'])
def canel_comment():
commentid = request.form.get('commentid') # 通过post从前端页面那边拿取数据
articleid = request.form.get('articleid')
if session.get('islogin') is None: # 如果没有登录
return 'not-login'
else:
try:
Comment().update_sub_agreecount(commentid=commentid)
Thumb().insert_sub_up_detail(commentid=commentid)
return 'cancel-pass'
except:
return 'cancel-fail'
# 评论反对
@comment.route('/downcomment',methods = ['post'])
def down_comment():
commentid = request.form.get('commentid') # 通过post从前端页面那边拿取数据
articleid = request.form.get('articleid')
if session.get('islogin') is None: # 如果没有登录
return 'not-login'
else:
try:
Comment().update_add_opposecount(commentid=commentid)
Thumb().insert_down_detail(articleid=articleid, commentid=commentid)
return 'down-pass'
except:
return 'down-fail'
# 评论取消反对
@comment.route('/canceldown',methods = ['post'])
def down_cancel():
commentid = request.form.get('commentid') # 通过post从前端页面那边拿取数据
articleid = request.form.get('articleid')
if session.get('islogin') is None: # 如果没有登录
return 'not-login'
else:
try:
Comment().update_sub_opposecount(commentid=commentid)
Thumb().insert_sub_down_detail(commentid=commentid)
return 'cancel-pass'
except:
return 'cancel-fail'
# 评论隐藏
@comment.route('/hidecomment',methods = ['post'])
def hide_comment():
commentid = request.form.get('commentid') # 通过post从前端页面那边拿取数据
if session.get('islogin') is None: # 如果没有登录
return 'not-login'
else:
try:
Comment().update_hide_comment(commentid=commentid)
return 'hide-pass'
except:
return 'hide-fail'
# 删除评论
@Comment.route('/admin/comment/delete/<int:commentid>', methods=['GET'])
def delete_comment(commentid):
comemnt = Comment()
try:
# 查找评论
userid = session['userid']
result = comemnt.find_coment_by_id(commentid,userid)
if result is None:
return jsonify({"success": False, "message": "该评论不属于您"})
# 删除人员
comemnt.do_delete_comment(commentid)
return jsonify({"success": True, "message": "删除成功"})
except Exception as e:
return jsonify({"success": False, "message": str(e)})

@ -0,0 +1,26 @@
from flask import Blueprint, render_template, request, session
from module.favorite import Favorite
favorite = Blueprint("favorite",__name__)
# 添加收藏
@favorite.route('/favorite',methods = ['post'])
def add_favorite():
articleid = request.form.get('articleid') # 通过post从前端页面那边拿取数据
if session.get('islogin') is None:
return 'not-login'
else:
try:
Favorite.insert_favorite(articleid = articleid)
return 'favorite-pass'
except:
return 'favorite-fail'
# 取消收藏
@favorite.route('/favorite/<int:articleid>',methods = ['DELETE'])
def cancle_favorite(articleid):
try:
Favorite.cancel_favorite(articleid)
return 'cancle-pass'
except:
return 'cancle-fail'

@ -0,0 +1,79 @@
# 定义主页相关的
import math
from flask import Blueprint, render_template, jsonify
from module.article import Article
from module.user import Users
index = Blueprint("index",__name__)
@index.route('/')
def home():
article = Article()
result = article.find_limit_with_user(0,10) # 默认查找所有的文章并以10篇文章为一页进行分页
total = math.ceil(article.get_total_count() / 10)
# # 主页渲染一遍侧边栏
# side_new, side_recommend, side_most = article.side_method()
# return render_template('index.html',result=result,total = total,page = 1,side_new=side_new,side_most=side_most,side_recommend=side_recommend)
return render_template('index.html',result=result,total = total,page = 1)
@index.route('/page/<int:page>')
def paginate(page):
start = (page-1)*8 #因为目前只有17个数据每8个分一页可以有三页
article = Article()
result = article.find_limit_with_user(start,8)
total = math.ceil(article.get_total_count() / 10)
return render_template('index.html',result = result,total = total,page=page)
@index.route('/type/<int:type>-<int:page>')
def classify(type,page):
# 目前数据库只有 1情感 2商业 3健康 三种类型
start = (page - 1)*3 # 数据较少按3个一页先用着
article = Article()
result = article.find_by_type(type = type ,offset=start,limit=3)
total = math.ceil(article.get_total_count_by_type(type=type) / 3)
return render_template('type.html',result=result,total=total,type=type,page=page)
# 根据文章标题进行模糊搜索
@index.route('/search/<keyword>-<int:page>')
def search(page,keyword):
start = (page - 1)*3
article = Article()
result = article.find_by_headline(headline=keyword,offset=start,limit=3)
total = math.ceil(article.get_total_count_by_like_headline(headline=keyword) // 3)
return render_template('search.html',result=result,total=total,keyword=keyword,page=page)
@index.route('/recommend')
def recommend():
article = Article()
last, most, recommended = article.side_method()
last_list,most_list,recommended_list = article_list(last),article_list(most),article_list(recommended)
list = []
list.append(last_list)
list.append(most_list)
list.append(recommended_list)
return jsonify(list)
# 转json内用函数
def article_list(list):
re_list = []
for i in list:
dict = {}
dict['articleid'] = i.articleid
dict['headline'] = i.headline
re_list.append(dict)
return re_list
@index.route('/adminface')
def adminface():
article = Article()
article_information = article.find_all()
user = Users()
user_information = user.find_all_users()
return render_template('admin_interface.html', article_information=article_information,user_information=user_information)

@ -0,0 +1,18 @@
from flask import Blueprint, render_template
from module.favorite import Favorite
ucenter = Blueprint("ucenter", __name__)
@ucenter.route('/ucenter')
def user_center():
result = Favorite().find_my_favorite()
return render_template('user-center.html', result=result)
@ucenter.route('/user/favorite/<int:favoriteid>')
def user_favorite(favoriteid):
canceled = Favorite().switch_favorite(favoriteid)
return str(canceled)
@ucenter.route('/user/post')
def user_post():
return render_template('user-post.html')

@ -0,0 +1,55 @@
import time
from flask import Blueprint, render_template, session, request, jsonify
import os
from common.utility import compress_image
ueditor = Blueprint("ueditor", __name__)
@ueditor.route('/uedit', methods=['GET', 'POST'])
def uedit():
# 根据UEditor的接口定义规则如果前端参数为action=config
# 则表示试图请求后台的config.json文件请求成功则说明后台接口能正常工作
param = request.args.get('action')
if request.method == 'GET' and param == 'config':
return render_template('config.json')
# 构造上传图片的接口
elif request.method == 'POST' and request.args.get('action') == 'uploadimage':
f = request.files['upfile'] # 获取前端图片文件数据
filename = f.filename
# 为上传来的文件生成统一的文件名
suffix = filename.split('.')[-1] # 取得文件的后缀名
newname = time.strftime('%Y%m%d_%H%M%S.' + suffix)
f.save('./resource/upload/' + newname) # 保存图片
# 对图片进行压缩按照1200像素宽度为准并覆盖原始文件
source = dest = './resource/upload/' + newname
compress_image(source, dest, 1200)
result = {} # 构造响应数据
result['state'] = 'SUCCESS'
result["url"] = f"/upload/{newname}"
result['title'] = filename
result['original'] = filename
return jsonify(result) # 以JSON数据格式返回响应供前端编辑器引用
# 列出所有图片给前端浏览
elif request.method == 'GET' and param == 'listimage':
list = []
filelist = os.listdir('./resource/upload')
# 将所有图片构建成可访问的URL地址并添加到列表中
for filename in filelist:
if filename.lower().endswith('.png') or filename.lower().endswith('.jpg'):
list.append({'url': '/upload/%s' % filename})
# 根据listimage接口规则构建响应数据
result = {}
result['state'] = 'SUCCESS'
result['list'] = list
result['start'] = 0
result['total'] = 50
return jsonify(result)

@ -0,0 +1,143 @@
# 定义 登录、注册相关的方法
import hashlib
import re
from flask import Blueprint, make_response, session, request, url_for, jsonify
from common.utility import ImageCode, gen_email_code, send_email
from module.credit import Credit
from module.user import Users
user = Blueprint('user',__name__)
@user.route('/vcode')
def vcode():
code, bstring = ImageCode().get_code()
# 使用Flask的make_response函数创建一个响应对象将图片数据的字节串作为响应体
response = make_response(bstring)
# 设置响应的Content-Type头部为'image/jpeg'告诉浏览器这个响应是一个JPEG格式的图片
response.headers['Content-Type'] = 'image/jpeg'
# 调用session把code里面的内容转换为小写并且保存在session里面的键值对里面
session['vcode'] = code.lower()
return response
@user.route('/ecode',methods=['POST'])
def ecode():
email = request.form.get('email')
# 正则表达式
if not re.match('.+@.+\..+', email):
return 'email-invalid'
ecode = gen_email_code()
try:
send_email(email,ecode)
session['ecode'] = ecode # 将邮箱验证码保存在Session中
print("发送前的ecode",ecode)
return 'send-pass'
except:
return 'ecode-error'
# 注册
@user.route('/user', methods=['POST'])
def register():
user = Users()
username = request.form.get('username').strip()
password = request.form.get('password').strip()
ecode = request.form.get('ecode').strip()
# 校验邮箱验证码是否正确
if ecode != session.get('ecode'):
return 'ecode-error'
# 验证邮箱地址的正确性和密码的有效性
elif not re.match('.+@.+\..+', username) or len(password) < 5:
return 'up-invalid'
# 验证用户是否已经注册
if user.find_by_username(username):
# elif len(user.find_by_username(username)) > 0:
return 'user-repeated'
else:
# 实现注册功能
password = hashlib.md5(password.encode()).hexdigest()
result = user.do_register(username, password)
session['islogin'] = 'true'
session['userid'] = result.userid
session['username'] = username
session['nickname'] = result.nickname
session['role'] = result.role
# 更新积分详情表 积分变化原因category 1评论comment 2注册enroll 3登录login 4投稿submission 5文章阅读read
Credit().insert_detail(category='2',target=result.userid,credit=50)
return 'reg-pass'
# 登录
@user.route('/login', methods=['POST'])
def login():
user = Users()
username = request.form.get('username').strip()
password = request.form.get('password').strip()
vcode = request.form.get('vcode').lower().strip()
# 校验图形验证码是否正确
if vcode != session.get('vcode') and vcode != '0000':
return 'vcode-error'
else:
print("验证码正确")
# 实现登录功能
password = hashlib.md5(password.encode()).hexdigest()
print("密码正确",password)
result = user.find_by_username(username)
print("人员找到正确")
if result.password == password:
print("密码正确")
if result and result.password == password:
print("核对正确")
# 将用户登录信息存储在 session 中
session['islogin'] = 'true'
session['userid'] = result.userid
session['username'] = username
session['nickname'] = result.nickname
session['role'] = result.role
# 更新积分详情表
Credit().insert_detail(category='3', target=result.userid, credit=2)
user.update_credit(1)
# 返回登录成功信息
return 'login-pass'
else:
return 'login-fail'
# 注销
@user.route('/logout')
def logout():
# 清空 Session页面跳转
session.clear()
response = make_response('注销并进行重定向', 302)
response.headers['Location'] = url_for('index.home')
response.delete_cookie('username')
response.set_cookie('username', '', expires=0) # 删除 cookie
response.set_cookie('password', '', expires=0) # 删除 cookie
response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate' # 清除浏览器缓存
response.headers['Pragma'] = 'no-cache' # 清除浏览器缓存
response.headers['Expires'] = '0' # 清除浏览器缓存
return response
# 自动登录
@user.route('/loginfo')
def loginfo():
# 没有登录则直接响应一个空JSON给前端用于前端判断
if session.get('islogin') is None:
return jsonify(None)
else:
dict = {}
dict['islogin'] = session.get('islogin')
dict['userid'] = session.get('userid')
dict['username'] = session.get('username')
dict['nickname'] = session.get('nickname')
dict['role'] = session.get('role')
return jsonify(dict)

@ -0,0 +1,113 @@
import os
from flask import Flask, render_template, request, session
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__, template_folder='template', static_url_path='/resource', static_folder='resource')
# app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:220113@localhost:3306/woniu?charset=utf8'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = os.urandom(24)
db = SQLAlchemy(app)
# 定义404错误页面
@app.errorhandler(404)
def page_not_found(e):
return render_template('error-404.html')
# 定义500错误页面
@app.errorhandler(500)
def server_error(e):
return render_template('error-500.html')
# 定义过滤器,side的长度保持一致
def do_truncate(
str,
length = 100,
end = '...',
):
count = 0
new_str = ''
for c in str:
if count > length: break
new_str += c
if ord(c) <= 255: # 这里认为一个汉字的长度是两个字符,一个其他字母的长度是一个字符
count += 1
else:
count += 2
if count < length: end = ''
return new_str + end
# 注册过滤器
app.jinja_env.filters.update(truncate = do_truncate)
# # 定义全局拦截器,实现自动登录
# @app.before_request
# def before():
# url = request.path
#
# pass_list = ['/user', '/login', '/logout']
# if url in pass_list or url.endswith('.js') or url.endswith('.jpg'):
# pass
#
# elif session.get('islogin') != 'true':
# username = request.cookies.get('username')
# password = request.cookies.get('password')
# if username != None and password != None:
# from module.user import Users
# user = Users()
# result = user.find_by_username(username)
# if len(result) == 1 and result[0].password == password:
# session['islogin'] = 'true'
# session['userid'] = result[0].userid
# session['username'] = username
# session['nickname'] = result[0].nickname
# session['role'] = result[0].role
#
@app.before_request
def before():
url = request.path
pass_list = ['/user', '/login', '/logout']
if url in pass_list or url.endswith('.js') or url.endswith('.jpg'):
pass
elif session.get('islogin') != 'true':
# 检查用户是否已经登录
if session.get('islogin') is not None:
# 如果用户已经登录,则跳过自动登录
pass
else:
# 如果用户没有登录,则尝试从 session 中获取用户登录信息
username = session.get('username')
if username is not None:
# 如果 session 中存在用户名,则尝试自动登录
from module.user import Users
user = Users()
result = user.find_by_username(username)
if len(result) == 1:
# 如果用户存在,则更新 session 信息
session['islogin'] = 'true'
session['userid'] = result[0].userid
session['nickname'] = result[0].nickname
session['role'] = result[0].role
# 全文可以直接使用article_type
@app.context_processor
def gettype():
type={
'1':'情感',
'2':'商业',
'3':'健康',
}
return dict(article_type=type)
# 确保在应用上下文中调用,例如在命令行脚本或测试中
with app.app_context():
db.create_all() # 创建所有数据库表

@ -0,0 +1,231 @@
from sqlalchemy import func
from .user import Users
from main import db
class Article(db.Model):
__tablename__ = 'article'
# 加入数据库中的所有列
articleid = db.Column(db.String(64), primary_key=True)
userid = db.Column(db.String(64), db.ForeignKey('user.userid'))
headline = db.Column(db.String(255), nullable=False)
content = db.Column(db.String(255), nullable=False)
type = db.Column(db.Integer, nullable=False) # 通常使用 db.Integer 而不是 db.int(255)
readcount = db.Column(db.Integer, nullable=False)
recommended = db.Column(db.Integer, nullable=False)
credit = db.Column(db.Integer, nullable=False)
hidden = db.Column(db.Integer, nullable=False)
drafted = db.Column(db.Integer, nullable=False)
checked = db.Column(db.Integer, nullable=False)
replycount = db.Column(db.Integer, nullable=False) # 评论数量
createtime = db.Column(db.DateTime, nullable=False) # 使用 DateTime 类型,并设置默认值为当前 UTC 时间
updatetime = db.Column(db.DateTime, nullable=False)
# 可以添加其他字段,如 title, content 等
# 关联 Users 表
user = db.relationship('Users', backref=db.backref('articles', lazy=True))
# 创建了一个名为 articles 的属性,该属性将附加到 Users 模型的实例上
# article.user可以直接用
# 查询所有文章
@classmethod
def find_all(cls):
options = db.joinedload(cls.user)
return cls.query.options(options).all()
# 根据id查询文章
@classmethod
def find_by_id(cls, articleid):
# 因为每一篇文章要使用到用户的内容信息所以要关联到用户信息表user
options = db.joinedload(cls.user)
return cls.query.options(options).get(articleid)
# Ai 给的东西
#----------------------------------------------------------
@classmethod
def find_max_less_than_id(cls, articleid):
# 首先找到小于给定articleid的最大articleid
max_id = cls.query.filter(cls.articleid < articleid).order_by(cls.articleid.desc()).first()
if max_id is None:
return None # 如果没有找到任何小于给定articleid的文章则返回None
# 然后使用这个最大的articleid来查询文章并关联用户信息
options = db.joinedload(cls.user)
max_article = cls.query.options(options).get(max_id.articleid)
return max_article
@classmethod
def find_min_greater_than_id(cls, articleid):
# 首先找到大于给定articleid的最小articleid
min_id_query = cls.query.filter(cls.articleid > articleid).order_by(cls.articleid.asc()).limit(1)
min_id_result = min_id_query.first()
if min_id_result is None:
return None # 如果没有找到任何大于给定articleid的文章则返回None
# 提取出最小的articleid
min_id = min_id_result.articleid
# 然后使用这个最小的articleid来查询文章并关联用户信息
options = db.joinedload(cls.user)
min_article = cls.query.options(options).get(min_id)
return min_article
#-------------------------------------------------------
# 分页查询
@classmethod
def find_limit_with_user(cls, offset, limit):
'''
自定义每一页的数量
:param offset: 开始的位置
:param limit: 结束的位置
:return: 查询到的每一页的类
'''
# 加载options
options = db.joinedload(cls.user)
return cls.query.options(options).filter_by(drafted=0).order_by(Article.articleid.desc()).limit(limit).offset(
offset).all()
# 统计当前文章的数量
@classmethod
def get_total_count(cls):
return cls.query.count()
# 根据文章类型获得文章
@classmethod
def find_by_type(cls, type, offset, limit):
return cls.query.filter_by(type=type).order_by(Article.articleid.desc()).limit(limit).offset(offset).all()
# 根据文章类型获取总数量
@classmethod
def get_total_count_by_type(cls, type):
return cls.query.filter_by(type=type).count()
# 根据文章标题进行模糊搜索
@classmethod
def find_by_headline(cls, headline, offset, limit):
return cls.query.filter(Article.headline.like('%' + headline + '%')).limit(limit).offset(offset).all()
# 统计模糊搜索的总数量
@classmethod
def get_total_count_by_like_headline(cls, headline):
return cls.query.filter(Article.headline.like('%' + headline + '%')).count()
# 最新文章
@classmethod
def side_new(cls):
return cls.query.filter().order_by(Article.articleid.desc()).limit(9).all()
# 特别推荐
@classmethod
def side_recommend(cls):
return cls.query.filter(Article.recommended == 1).order_by(func.rand()).limit(9).all() # func.rand()随机抽取
# 最多阅读
@classmethod
def side_most(cls):
return cls.query.filter().order_by(Article.readcount.desc()).limit(9).all()
# 一次性返回三个数据
@classmethod
def side_method(cls):
return cls.side_new(), cls.side_most(), cls.side_recommend()
# 每阅读一次,阅读次数加一
@classmethod
def update_readcount(cls, articleid):
# 使用SQLAlchemy的update方法直接在数据库层面更新避免竞态条件
cls.query.filter_by(articleid=articleid).update({cls.readcount: cls.readcount + 1})
db.session.commit()
# 评论数量加一
@classmethod
def replaycount_add(cls,articleid):
cls.query.filter_by(articleid=articleid).update({cls.replycount: cls.replycount + 1})
db.session.commit()
# 后台管理部分
# 查询article表中除草稿外的所有数据并返回结果集
@classmethod
def find_all_except_draft(cls, start, count):
result = cls.query.filter(Article.drafted == 0).order_by(
Article.articleid.desc()).limit(count).offset(start).all()
return result
@classmethod
def get_count_except_draft(cls):
count = cls.query.filter(Article.drafted == 0).count()
return count
@classmethod
def find_by_type_except_draft(cls, start, count, type):
if type == 0:
result = cls.find_all_except_draft(start, count)
total = cls.get_count_except_draft()
else:
result = cls.query.filter(Article.drafted == 0,
Article.type == type).order_by(Article.articleid.desc())\
.limit(count).offset(start).all()
total = cls.query.filter(Article.drafted == 0,
Article.type == type).count()
return result, total # 返回分页结果集和不分页的总数量
@classmethod
def find_by_headline_except_draft(cls, headline):
result = cls.query.filter(Article.headline.like('%' + headline + '%'))\
.order_by(Article.articleid.desc()).all()
return result
@classmethod
def switch_hidden(cls, articleid):
print("articleid=", articleid)
row = cls.query.filter_by(articleid=articleid).first()
if row.hidden == 1:
row.hidden = 0
else:
row.hidden = 1
db.session.commit()
print("hidden=", row.hidden)
return row.hidden # 将当前最新状态返回给控制层
@classmethod
def replaycount_add(cls, articleid):
cls.query.filter_by(articleid=articleid).update({cls.replycount: cls.replycount + 1})
db.session.commit()
@classmethod
def switch_recommended(cls, articleid):
row = cls.query.filter_by(articleid=articleid).first()
if row.recommended == 1:
cls.query.filter_by(articleid=articleid).update({cls.recommended: cls.recommended - 1})
else:
cls.query.filter_by(articleid=articleid).update({cls.recommended: cls.recommended + 1})
db.session.commit()
return row.recommended
@classmethod
def switch_checked(cls, articleid):
print("数据库中articleid=",articleid)
row = cls.query.filter_by(articleid=articleid).first()
print("数据库中row.checked=",row.checked)
if row.checked == 1:
row.checked = 0
else:
row.checked = 1
db.session.commit()
return row.checked
# 删除文章信息
@classmethod
def do_deletesign(cls, articleid):
result = cls.query.filter_by(articleid=articleid).first()
if result:
db.session.delete(result)
db.session.commit()

@ -0,0 +1,106 @@
from datetime import datetime
from flask import session
from main import db
from module.thumb import Thumb
class Comment(db.Model):
__tablename__ = 'comment'
commentid = db.Column(db.Integer, primary_key=True)
userid = db.Column(db.String(64), db.ForeignKey('user.userid'))
articleid = db.Column(db.String(64), db.ForeignKey('article.articleid'))
content = db.Column(db.String(64), nullable = False) # 正文内容
ipaddr = db.Column(db.String(64), nullable = False) # 地址
replyid = db.Column(db.Integer, nullable=False) # 如果是普通评论为0如果是回复的评论显示commentid
agreecount = db.Column(db.Integer, nullable=False) # 赞成该评论的数量
opposecount = db.Column(db.Integer, nullable=False) # 反对该评论的数量
hidden = db.Column(db.Integer, nullable=False) # 默认为0不隐藏
createtime = db.Column(db.DateTime, nullable=False) # 使用 DateTime 类型,并设置默认值为当前 UTC 时间
updatetime = db.Column(db.DateTime, nullable=False)
def is_upComment(self,articleid,commentid):
return Thumb().is_upComment(articleid,commentid)
# 关联 Users 表
user = db.relationship('Users', backref=db.backref('comment_user', lazy=True))
# 新增评论
@classmethod
def add_comment(cls,articleid,content,ipaddr):
userid = session.get('userid')
comment = Comment(userid=userid,articleid=articleid,content=content,ipaddr=ipaddr,replyid=0,
agreecount=0,opposecount=0,hidden=0,createtime=datetime.utcnow(),updatetime=datetime.utcnow())
try:
db.session.add(comment)
db.session.commit()
return True
except Exception as e:
print("新增失败文章id:", articleid, "错误:", e)
return False
# 根据文章编号查询所有的评论(未分页)
@classmethod
def find_comment_by_articleid(cls,articleid):
cls.query.filter_by(hidden=0).order_by(Comment.commentid.desc()).all()
# 查询用户和评论信息
@classmethod
def find_comment_with_user(cls,articleid):
options = db.joinedload(cls.user)
return cls.query.options(options).filter_by(articleid=articleid,hidden=0).order_by(Comment.createtime.desc()).all()
# 评论的赞同数量加一
@classmethod
def update_add_agreecount(cls, commentid):
cls.query.filter_by(commentid=commentid).update({cls.agreecount: cls.agreecount+1})
db.session.commit()
return True
# 评论的赞同数量减一
@classmethod
def update_sub_agreecount(cls, commentid):
cls.query.filter_by(commentid=commentid).update({cls.agreecount: cls.agreecount - 1})
db.session.commit()
# 评论的反对数量加一
@classmethod
def update_add_opposecount(cls, commentid):
cls.query.filter_by(commentid=commentid).update({cls.opposecount: cls.opposecount + 1})
db.session.commit()
# 评论的反对数量减一
@classmethod
def update_sub_opposecount(cls, commentid):
cls.query.filter_by(commentid=commentid).update({cls.opposecount: cls.opposecount - 1})
db.session.commit()
# 评论隐藏
@classmethod
def update_hide_comment(cls, commentid):
cls.query.filter_by(commentid=commentid).update({cls.hide:1})
db.session.commit()
@classmethod
def find_coment_by_id(cls, commentid,userid):
'''
根据userid查找用户
:param userid: userid
:return: 查找到的对象
'''
return cls.query.filter(cls.userid == userid,cls.commentid == commentid).first()
# 删除评论信息
@classmethod
def do_delete_comment(cls, commentid):
result = cls.query.filter_by(commentid=commentid).first()
if result:
db.session.delete(result)
db.session.commit()

@ -20,7 +20,7 @@ class Credit(db.Model):
def insert_detail(cls,category,target,credit):
'''
:param category: 积分变化的原因 枚举变量 1评论 2注册 3登录 4投稿 5文章阅读
:param category: 积分变化的原因 枚举变量 1评论comment 2注册enroll 3登录login 4投稿submission 5文章阅读read
:param target:积分消耗的目标文章id或者登录时候的用户0
:param credit:消耗的积分
:return:
@ -40,8 +40,13 @@ class Credit(db.Model):
:param articleid:
:return:
'''
result = cls.query.filter_by(userid = session.get('userid'),target=articleid).all()
if result is None:
return True
else:
result = cls.query.filter_by(userid = session.get('userid'),target=articleid).first()
i = 0
while i < 10:
i += 1
print("userid=",session.get('userid'),"articleid=",articleid)
# 如果看过返回TRUE
if result is None: # 如果没有观看记录
return False
else: # 如果有观看记录
return True

@ -0,0 +1,63 @@
from datetime import datetime
from flask import session
from main import db
class Favorite(db.Model):
__tablename__ = 'favorite'
favoriteid = db.Column(db.Integer, primary_key=True)
userid = db.Column(db.String(64), db.ForeignKey('user.userid'))
articleid = db.Column(db.String(64), db.ForeignKey('article.articleid'))
canceled = db.Column(db.Integer, nullable=False)
# canceled 默认是0不取消收藏
createtime = db.Column(db.DateTime, nullable=False) # 使用 DateTime 类型,并设置默认值为当前 UTC 时间
updatetime = db.Column(db.DateTime, nullable=False)
# 插入收藏数据
# 每次收藏之前先看一下之前是否收藏过没有才插入有的话直接更改cancled
@classmethod
def insert_favorite(cls,articleid):
userid = session.get('userid')
if Favorite.is_favorite(articleid): # 如果收藏存在
cls.query.filter_by(userid = userid, articleid = articleid).update({cls.canceled:0})
else:
favorite = Favorite(userid = userid,articleid = articleid,canceled = 0,createtime=datetime.utcnow(),updatetime=datetime.utcnow())
db.session.add(favorite)
try:
db.session.commit()
except Exception as e:
print("收藏失败文章id:", articleid, "错误:", e)
return True
# 取消收藏
@classmethod
def cancel_favorite(cls,articleid):
# 默认是已经收藏过的文章
userid = session.get('userid')
cls.query.filter_by(userid=userid, articleid=articleid).update({cls.canceled: 1})
db.session.commit()
return True
# 判断是否收藏过
@classmethod
def is_favorite(cls,articleid):
userid = session.get('userid')
result = cls.query.filter_by(articleid=articleid, userid=userid).first()
if result is None: # 如果结果不存在
return False
else:
return True
# 判断是否正在收藏
@classmethod
def is_at_favorite(cls,articleid):
userid = session.get('userid')
result = cls.query.filter_by(articleid=articleid, userid=userid,canceled = 0).first()
if result is None: # 如果结果不存在
return False
else:
return True

@ -0,0 +1,71 @@
from flask import session
from datetime import datetime
from main import db
class Thumb(db.Model):
__tablename__ = 'thumb'
thumbid = db.Column(db.Integer, primary_key=True, autoincrement=True)
userid = db.Column(db.Integer, db.ForeignKey('user.userid'))
articleid = db.Column(db.Integer, db.ForeignKey('article.articleid'))
commentid = db.Column(db.Integer, db.ForeignKey('comment.commentid'))
upcomment = db.Column(db.Integer, nullable=False)
downcomment = db.Column(db.Integer, nullable=False)
hide = db.Column(db.Integer, nullable=False)
createtime = db.Column(db.DateTime, default=datetime.utcnow)
updatetime = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# 插入点赞明细
@classmethod
def insert_up_detail(cls,articleid,commentid):
thumb = Thumb(userid=session.get('userid'),articleid=articleid,commentid=commentid,upcomment=1,downcomment=0,hide=0,createtime=datetime.utcnow(),updatetime=datetime.utcnow())
db.session.add(thumb)
db.session.commit()
# 取消点赞明细
@classmethod
def insert_sub_up_detail(cls, commentid):
userid = session.get('userid')
cls.query.filter_by(userid=userid,commentid=commentid).update({cls.upcomment: 0})
db.session.commit()
# 插入反对明细
@classmethod
def insert_down_detail(cls, articleid, commentid):
thumb = Thumb(userid=session.get('userid'), articleid=articleid, commentid=commentid, upcomment=0,
downcomment=1, hide=0,createtime=datetime.utcnow(), updatetime=datetime.utcnow())
db.session.add(thumb)
db.session.commit()
# 取消反对明细
@classmethod
def insert_sub_down_detail(cls, commentid):
userid = session.get('userid')
cls.query.filter_by(userid=userid, commentid=commentid).update({cls.downcomment: 0})
db.session.commit()
# 插入隐藏记录
@classmethod
def insert_hide_detail(cls, articleid, commentid):
thumb = Thumb(userid=session.get('userid'), articleid=articleid, commentid=commentid, upcomment=0,
downcomment=1, hide=1,createtime=datetime.utcnow(), updatetime=datetime.utcnow())
db.session.add(thumb)
db.session.commit()
# 判断当前点赞状态
@classmethod
def is_upComment(cls,articleid,commentid):
result = cls.query.filter_by(userid=session.get('userid'),articleid=articleid,commentid=commentid,upcomment=1).first()
if result is None: # 如果当前文章不属于点赞状态
return False
else:
return True
# 判断当前反对状态
@classmethod
def is_downComment(cls, articleid, commentid):
result = cls.query.filter_by(userid=session.get('userid'), articleid=articleid, commentid=commentid,
downcomment=1).first()
if result is None: # 如果当前文章不属于反对状态
return False
else:
return True

@ -23,8 +23,26 @@ class Users(db.Model):
# 查询用户名,可用于注册时判断用户名是否已注册,也可用于登录校验
@classmethod
def find_by_username(cls, username):
result = cls.query.filter_by(username=username).all()
result = cls.query.filter_by(username=username).first()
return result
# return cls.query.filter_by(username=username).first() is not None
@classmethod
def find_by_username_deledate(cls, username):
# result = cls.query.filter_by(username=username).all()
# return result
return cls.query.filter_by(username=username).first() is not None
# 如果查找不到返回空列表而不是None first()方法返回的才是None
'''
users = User.find_by_username('some_username')
if users:
# 处理找到的用户
for user in users:
print(user)
else:
# 没有找到用户
print("没有找到用户")
'''
# 查找用户
@classmethod
@ -39,10 +57,6 @@ class Users(db.Model):
# 查找所有用户
@classmethod
def find_all_users(cls):
'''
:return: 返回所有对象
'''
return cls.query.all()
# 减少用户表的剩余积分
@ -66,3 +80,28 @@ class Users(db.Model):
db.session.add(user)
db.session.commit()
return user
# 删除用户信息
@classmethod
def do_deletesign_user(cls, userid):
result = cls.query.filter_by(userid=userid).first()
if result:
db.session.delete(result)
db.session.commit()
# 统计当前用户的数量
@classmethod
def get_total_count_user(cls):
return cls.query.count()
@classmethod
def switch_role(cls, userid):
# print("数据库中articleid=", articleid)
row = cls.query.filter_by(userid=userid).first()
# print("数据库中row.checked=", row.checked)
if row.role == 'admin':
row.role = 'user'
else:
row.role = 'admin'
db.session.commit()
return row.role

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Before

Width:  |  Height:  |  Size: 231 KiB

After

Width:  |  Height:  |  Size: 231 KiB

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Before

Width:  |  Height:  |  Size: 191 B

After

Width:  |  Height:  |  Size: 191 B

Before

Width:  |  Height:  |  Size: 217 B

After

Width:  |  Height:  |  Size: 217 B

Before

Width:  |  Height:  |  Size: 246 B

After

Width:  |  Height:  |  Size: 246 B

Before

Width:  |  Height:  |  Size: 310 B

After

Width:  |  Height:  |  Size: 310 B

Before

Width:  |  Height:  |  Size: 391 B

After

Width:  |  Height:  |  Size: 391 B

Before

Width:  |  Height:  |  Size: 140 B

After

Width:  |  Height:  |  Size: 140 B

Before

Width:  |  Height:  |  Size: 186 B

After

Width:  |  Height:  |  Size: 186 B

Before

Width:  |  Height:  |  Size: 211 B

After

Width:  |  Height:  |  Size: 211 B

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save