db.session.query(Users).order_by('id desc').all()报错

原因: 新版本的sqlalchemy 不支持这种写法

方案一:导入text模块
db.session.query(Users).order_by(text(‘id desc’)).all()

方案二:
db.session.query(Users).order_by(Users.id.desc).all()

参考我下面的代码,重新写一下你的viewfrom flask import Blueprint, request from flask_jwt_extended import jwt_required from extensions import db from sys_user.sys_user import SysUser from utils.api_response import api_response from datetime import datetime user_bp = Blueprint('sys-user', __name__, url_prefix='/api/sys-users') # 用户列表查询(带分页) @user_bp.route('', methods=['GET']) @jwt_required() def get_users(): try: username = request.args.get('username') page = request.args.get('page', 1, type=int) per_page = request.args.get('per_page', 10, type=int) if not username or len(username)==0: query = SysUser.query.filter_by(delete_flag=0).order_by(SysUser.user_id.desc()) else: query = SysUser.query.filter_by(delete_flag=0).filter(SysUser.username.contains(username)).order_by(SysUser.user_id.desc()) pagination = query.paginate(page=page, per_page=per_page, error_out=False) users = [user.to_dict() for user in pagination.items] return api_response({ 'total': pagination.total, 'page': pagination.page, 'per_page': pagination.per_page, 'items': users }) except Exception as e: return api_response(code=500, message=f"服务器错误: {str(e)}") # 创建用户 @user_bp.route('', methods=['POST']) @jwt_required() def create_user(): try: data = request.get_json() if not data or 'username' not in data or 'password' not in data: return api_response(code=400, message="缺少必要字段: username或password") if SysUser.query.filter_by(username=data['username']).first(): return api_response(code=400, message="用户名已存在") user = SysUser() user.username = data['username'] user.set_password(data['password']) # 密码哈希处理 # 可选字段处理 fields = ['real_name', 'email', 'phone', 'sex'] for field in fields: if field in data: setattr(user, field, data[field]) db.session.add(user) db.session.commit() return api_response(user.to_dict(), code=200) except Exception as e: db.session.rollback() return api_response(code=500, message=f"创建用户失败: {str(e)}") # 用户详情 @user_bp.route('/<int:user_id>', methods=['GET']) @jwt_required() def get_user(user_id): try: user = SysUser.query.filter_by(user_id=user_id, delete_flag=0).first() if not user: return api_response(code=404, message="用户不存在") return api_response(user.to_dict()) except Exception as e: return api_response(code=500, message=f"查询失败: {str(e)}") # 更新用户 @user_bp.route('/<int:user_id>', methods=['PUT']) @jwt_required() def update_user(user_id): try: user = SysUser.query.get(user_id) if not user or user.delete_flag == 1: return api_response(code=404, message="用户不存在") data = request.get_json() if not data: return api_response(code=400, message="无有效数据") # 密码单独处理 if 'password' in data: user.set_password(data['password']) # 可更新字段白名单 allowed_fields = ['real_name', 'email', 'phone', 'sex', 'status'] for field in allowed_fields: if field in data: setattr(user, field, data[field]) db.session.commit() return api_response(user.to_dict()) except Exception as e: db.session.rollback() return api_response(code=500, message=f"更新失败: {str(e)}") # 删除用户(软删除) @user_bp.route('/<int:user_id>', methods=['DELETE']) @jwt_required() def delete_user(user_id): try: user = SysUser.query.get(user_id) if not user or user.delete_flag == 1: return api_response(code=404, message="用户不存在") user.delete_flag = 1 db.session.commit() return api_response(message="删除成功") except Exception as e: db.session.rollback() return api_response(code=500, message=f"删除失败: {str(e)}")
03-27
以下是基于PyCharm开发的网上书店项目核心代码示例及实现思路,结合了Flask和SQLAlchemy框架实现书籍查询、购物车管理等核心功能: ### 一、基础项目结构(PyCharm工程) ``` bookstore/ ├── app.py # Flask主程序 ├── config.py # 配置文件 ├── models.py # 数据库模型 ├── templates/ # HTML模板 │ ├── index.html │ └── search.html └── requirements.txt # 依赖库列表 ``` ### 二、核心代码实现 #### 1. 数据库模型(models.py) ```python from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class Book(db.Model): __tablename__ = 'books' id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(100), index=True) author = db.Column(db.String(50)) price = db.Column(db.Float) stock = db.Column(db.Integer) class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(50), unique=True) cart = db.relationship('CartItem', backref='user') class CartItem(db.Model): __tablename__ = 'cart_items' id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('users.id')) book_id = db.Column(db.Integer, db.ForeignKey('books.id')) quantity = db.Column(db.Integer) ``` #### 2. 书籍搜索功能(app.py) ```python @app.route('/search') def search_books(): search_query = request.args.get('q') # 实现多字段搜索(标题/作者) results = Book.query.filter( db.or_( Book.title.ilike(f'%{search_query}%'), Book.author.ilike(f'%{search_query}%') ) ).all() return render_template('search.html', results=results) ``` #### 3. 购物车操作(app.py) ```python @app.route('/add_to_cart', methods=['POST']) def add_to_cart(): book_id = request.form.get('book_id') quantity = int(request.form.get('quantity', 1)) # 获取当前用户(需要实现用户认证) user = User.query.get(current_user.id) # 检查库存 book = Book.query.get(book_id) if book.stock >= quantity: # 添加购物车项 item = CartItem(user_id=user.id, book_id=book_id, quantity=quantity) db.session.add(item) db.session.commit() return redirect(url_for('cart')) else: return "库存不足", 400 ``` ### 三、PyCharm环境配置步骤 1. 创建新项目选择 `Flask` 模板 2. 安装依赖库: ```bash pip install flask flask-sqlalchemy ``` 3. 配置数据库连接(修改config.py): ```python SQLALCHEMY_DATABASE_URI = 'sqlite:///bookstore.db' ``` 4. 初始化数据库: ```python with app.app_context(): db.create_all() ``` ### 四、进阶功能建议 1. 订单处理模块(参考电商模式) 2. 支付接口集成(如支付宝/微信支付SDK) 3. 推荐系统实现(基于用户行为分析) : 书籍查询功能参考了SQLAlchemy的多条件过滤实现 : 模块化设计借鉴了查理芒格的知识整合方法
05-14
from flask import Flask from flask import jsonify, request from flask_cors import CORS from flask_sqlalchemy import SQLAlchemy from werkzeug.utils import secure_filename import os import requests from bs4 import BeautifulSoup import re import json from snownlp import SnowNLP from openpyxl import Workbook import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.edge.options import Options as EdgeOptions import xml.etree.ElementTree as ET from collections import Counter import jieba # 中文分词库 from datetime import datetime import pandas as pd import matplotlib.pyplot as plt import emoji app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:root@127.0.0.1/analysisdb' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True # 设置这一项是每次请求结束后都会自动提交数据库中的变动 app.config['UPLOAD_FOLDER'] = 'static/uploadfiles' # 上传文件保存目录 app.config['ALLOWED_EXTENSIONS'] = {'png', 'jpg', 'jpeg', 'gif'} # 允许的文件类型 app.config['MAX_CONTENT_LENGTH'] = 2 * 1024 * 1024 # 文件大小限制: 2MB app.secret_key = 'asfda8r9q3y9qy#%GFSD^%WTAfasdfasqwe' # r'/*' 是通配符,让本服务器所有的URL 都允许跨域请求 CORS(app, resources=r'/*') # 实例化 db = SQLAlchemy(app) # 确保上传目录存在 os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) # 设置headers headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3', 'Referer': 'https://www.bilibili.com/' } # 读取停用词表 stoppath = 'stoplist.txt' stopwords = open(stoppath, "r", encoding='utf-8').read() wordlist = [] # 存储弹幕信息 comments = [] # 存放评论信息 # 用户表 class Users(db.Model): __tablename__ = "users" id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(50), nullable=False) password = db.Column(db.String(10), nullable=False) role = db.Column(db.String(10), nullable=False) #(admin:管理员 user:用户) truename = db.Column(db.String(50)) sex = db.Column(db.String(10)) phone = db.Column(db.String(50)) headface = db.Column(db.String(255)) addtime = db.Column(db.String(20), nullable=False) def __init__(self, username, password, truename, phone, sex, role, addtime): self.username = username self.password = password self.truename = truename self.phone = phone self.sex = sex self.role = role self.addtime = addtime # 视频表 class Videos(db.Model): __tablename__ = "videos" id = db.Column(db.Integer, primary_key=True, autoincrement=True) cid = db.Column(db.String(100), nullable=False) title = db.Column(db.String(255), nullable=False) lovenum = db.Column(db.Integer) playnum = db.Column(db.Integer) addtime = db.Column(db.String(20), nullable=False) userid = db.Column(db.Integer, db.ForeignKey('upinfo.id')) bvid = db.Column(db.String(100), nullable=False) aid = db.Column(db.String(100), nullable=False) # 弹幕信息表 class Tanmu(db.Model): __tablename__ = "tanmu" id = db.Column(db.Integer, primary_key=True, autoincrement=True) cid = db.Column(db.String(100), nullable=False) txt = db.Column(db.String(255), nullable=False) level = db.Column(db.String(10), nullable=False) score = db.Column(db.String(10), nullable=False) def __init__(self, cid, txt, level, score): self.cid = cid self.txt = txt self.level = level self.score = score # 弹幕发表人员信息表 class Upinfo(db.Model): __tablename__ = "upinfo" id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(100), nullable=False) mid = db.Column(db.String(100), nullable=False) face = db.Column(db.String(255), nullable=True) videos = db.relationship('Videos', backref='upinfo', lazy=True) # 视频评论表 class Comments(db.Model): __tablename__ = "comments" id = db.Column(db.Integer, primary_key=True, autoincrement=True) cid = db.Column(db.String(100), nullable=False) username = db.Column(db.String(100), nullable=False) content = db.Column(db.TEXT, nullable=False) likenum = db.Column(db.String(10)) sendtime = db.Column(db.String(20)) level = db.Column(db.String(10), nullable=False) score = db.Column(db.String(10), nullable=False) def __init__(self, cid, username, content, likenum, sendtime, level, score): self.cid = cid self.username = username self.content = content self.likenum = likenum self.sendtime = sendtime self.level = level self.score = score # 日志表 class Syslog(db.Model): __tablename__ = "syslog" id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(100), nullable=False) operation = db.Column(db.String(200), nullable=False) method = db.Column(db.String(200), nullable=False) addtime = db.Column(db.String(20), nullable=False) def __init__(self, username, operation, method, addtime): self.username = username self.operation = operation self.method = method self.addtime = addtime # 意见反馈表 class Feedbacks(db.Model): __tablename__ = "feedbacks" id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(100), nullable=False) phone = db.Column(db.String(20), nullable=False) title = db.Column(db.String(255), nullable=False) content = db.Column(db.TEXT, nullable=False) addtime = db.Column(db.String(20), nullable=False) def __init__(self, username, phone, title, content, addtime): self.username = username self.phone = phone self.title = title self.content = content self.addtime = addtime with app.app_context(): db.create_all() # 登录 @app.route('/login', methods=['POST']) #'login'是接口路径,methods不写,则默认get请求 def login(): data = request.get_json() username = data.get("account") # 用户名 password = data.get("password") # 密码 role = data.get("role") # 角色 user = Users.query.filter_by(username=username).first() if user: if user.password == password: if user.role == role: user_data = {} user_data['id'] = user.id user_data['username'] = user.username user_data['password'] = user.password user_data['role'] = user.role user_data['truename'] = user.truename user_data['phone'] = user.phone user_data['sex'] = user.sex user_data['addtime'] = user.addtime return jsonify({"code": 200, "msg": "登录成功", "data": user_data}) else: return jsonify({"code": 500, "msg": "用户身份错误!"}) else: return jsonify({"code": 500, "msg": "密码错误!"}) else: return jsonify({"code": 500, "msg": "用户不存在!"}) # 注册 @app.route('/register', methods=['POST']) def register(): data = request.get_json() # 获取JSON数据 username = data.get("account") # 用户名 password = data.get("password") # 密码 user = Users.query.filter_by(username=username).first() if user: return jsonify({"code": 500, "msg": "用户已经存在!"}) else: # 获取当前时间字符串 cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") new_user = Users(username, password, '', '', '', 'user', cur_time) db.session.add(new_user) db.session.commit() return jsonify({"code": 200, "msg": "注册成功"}) # 获取所有用户 @app.route('/showUser', methods=['POST','GET']) def showUser(): # 接收查询条件 data = request.get_json() query = data.get("params").get("accountName") if query != "": page_objs = Users.query.filter_by(role='user').filter(Users.username.like('%{}%'.format(query))).paginate( page=int(data.get("params").get("page", 1)), per_page=int(data.get("params").get("limit", 15)), error_out=False, max_per_page=50 ).items totalcount = Users.query.filter_by(role='user').filter(Users.username.like('%{}%'.format(query))).count() else: page_objs = Users.query.filter_by(role='user').paginate( page=int(data.get("params").get("page", 1)), per_page=int(data.get("params").get("limit", 15)), error_out=False, max_per_page=50 ).items totalcount = Users.query.filter_by(role='user').count() output = [] for user in page_objs: user_data = {} user_data['id'] = user.id user_data['username'] = user.username user_data['truename'] = user.truename user_data['sex'] = user.sex user_data['phone'] = user.phone user_data['headface'] = user.headface user_data['addtime'] = user.addtime output.append(user_data) # 插入日志 cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") new_log = Syslog('admin', 'query', 'showUser', cur_time) db.session.add(new_log) db.session.commit() # 返回数据 data = {} data['list'] = output data['total'] = totalcount if totalcount == 0: return jsonify({"code": 200, "msg": "无数据", "data": []}) else: return jsonify({"code": 200, "msg": "处理成功", "data": data}) # 删除指定用户 @app.route("/deleteUser",methods=['POST','GET']) def deleteUser(): id = request.args.get("id") user = Users.query.get(id) if not user: return jsonify({"code": 500, "msg": "用户不存在!"}) db.session.delete(user) db.session.commit() # 插入日志 cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") new_log = Syslog('admin', 'delete', 'deleteUser', cur_time) db.session.add(new_log) db.session.commit() return jsonify({"code": 200, "msg": "删除成功"}) # 获取所有视频 @app.route('/showVideo', methods=['POST','GET']) def showVideo(): # 接收查询条件 data = request.get_json() query = data.get("params").get("title") if query != "": page_objs = Videos.query.filter(Videos.title.like('%{}%'.format(query))).paginate( page=int(data.get("params").get("page", 1)), per_page=int(data.get("params").get("limit", 15)), error_out=False, max_per_page=50 ).items totalcount = Videos.query.filter(Videos.title.like('%{}%'.format(query))).count() else: page_objs = Videos.query.paginate( page=int(data.get("params").get("page", 1)), per_page=int(data.get("params").get("limit", 15)), error_out=False, max_per_page=50 ).items totalcount = Videos.query.count() output = [] for video in page_objs: video_data = {} video_data['id'] = video.id video_data['cid'] = video.cid video_data['title'] = video.title video_data['lovenum'] = video.lovenum video_data['playnum'] = video.playnum video_data['addtime'] = video.addtime video_data['userid'] = video.userid video_data['bvid'] = video.bvid video_data['aid'] = video.aid upinfo = Upinfo.query.filter_by(id=video.userid).first() video_data['username'] = upinfo.username output.append(video_data) # 插入日志 cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") new_log = Syslog('admin', 'query', 'showVideo', cur_time) db.session.add(new_log) db.session.commit() # 返回数据 data = {} data['list'] = output data['total'] = totalcount if totalcount == 0: return jsonify({"code": 200, "msg": "无数据", "data": []}) else: return jsonify({"code": 200, "msg": "处理成功", "data": data}) # 删除视频 @app.route("/deleteVideo",methods=['POST','GET']) def deleteVideo(): id = request.args.get("id") video = Videos.query.get(id) if not video: return jsonify({"code": 500, "msg": "视频不存在!"}) db.session.delete(video) db.session.commit() # 插入日志 cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") new_log = Syslog('admin', 'delete', 'deleteVideo', cur_time) db.session.add(new_log) db.session.commit() return jsonify({"code": 200, "msg": "删除成功"}) # 获取所有弹幕 @app.route('/showTanmu', methods=['POST','GET']) def showTanmu(): data = request.get_json() query = data.get("params").get("cid") if query != "": page_objs = Tanmu.query.filter_by(cid=query).paginate( page=int(data.get("params").get("page", 1)), per_page=int(data.get("params").get("limit", 15)), error_out=False, max_per_page=50 ).items totalcount = Tanmu.query.filter_by(cid=query).count() else: page_objs = Tanmu.query.paginate( page=int(data.get("params").get("page", 1)), per_page=int(data.get("params").get("limit", 15)), error_out=False, max_per_page=50 ).items totalcount = Tanmu.query.count() output = [] for tanmu in page_objs: video = Videos.query.filter_by(cid=tanmu.cid).first() tanmu_data = {} tanmu_data['id'] = tanmu.id tanmu_data['cid'] = video.cid tanmu_data['txt'] = tanmu.txt tanmu_data['level'] = tanmu.level tanmu_data['score'] = tanmu.score output.append(tanmu_data) # 插入日志 cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") new_log = Syslog('admin', 'query', 'showTanmu', cur_time) db.session.add(new_log) db.session.commit() # 返回数据 data = {} data['list'] = output data['total'] = totalcount if totalcount == 0: return jsonify({"code": 200, "msg": "无数据", "data": []}) else: return jsonify({"code": 200, "msg": "处理成功", "data": data}) # 爬取弹幕 @app.route('/crawling', methods=['GET']) def crawling(): pattern = r"^//(?:www\.)?bilibili\.com/video/BV(\w+)" # 设置浏览器驱动 driver = setup_driver() keyword = '人工智能' baseurl = ( f"https://search.bilibili.com/all?keyword={keyword}&from_source=webtop_search&spm_id_from=333.1007&search_source=5") driver.get(baseurl) time.sleep(50) # 等待页面加载 for page in range(1, 10): print(f"get {page} page...") scroll_page(driver) res = driver.page_source # 提取数据 soup = BeautifulSoup(res, 'html.parser') divs = soup.select('div.bili-video-card__wrap') for div in divs: alink = div.find('a')['href'] match = re.match(pattern, alink) if match: bvid = match.group(1) get_video_info('BV' + bvid) # 翻页 if page < 10: try: next_page = driver.find_element(By.CSS_SELECTOR, 'div.bili-video-card__wrap') next_page.click() time.sleep(5) # 等待新页面加载 except NoSuchElementException: print("已到达最后一页") break save_excel() return jsonify({"code": 200, "msg": "爬取成功"}) def setup_driver(): options = EdgeOptions() options.add_experimental_option('excludeSwitches', ['enable-automation']) driver = webdriver.Edge(options=options) try: with open('E://PyWorkspaces/AnalysisSys/stealth.min.js', 'r') as f: js = f.read() driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {'source': js}) except Exception as e: print(f"执行 JavaScript 脚本时出错: {e}") return driver def scroll_page(driver): """滚动页面以加载更多""" last_height = driver.execute_script("return document.body.scrollHeight") while True: driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") time.sleep(2) new_height = driver.execute_script("return document.body.scrollHeight") if new_height == last_height: break last_height = new_height def get_video_info(video_id): # 构造视频信息的URL video_url = f'https://api.bilibili.com/x/web-interface/view?bvid={video_id}' print(video_url) # 发送请求获取数据 response = requests.get(video_url, headers=headers) data = response.text # 解析JSON数据 video_info = json.loads(data) # 提取所需信息,比如视频标题、播放量等 bvid = video_info['data']['bvid'] aid = video_info['data']['aid'] cid = video_info['data']['cid'] title = video_info['data']['title'] play_count = video_info['data']['stat']['view'] like_count = video_info['data']['stat']['like'] pubdate = video_info['data']['pubdate'] addtime = datetime.fromtimestamp(pubdate) #获取up主信息 user_info = video_info['data']['owner'] mid = user_info['mid'] name = user_info['name'] face = user_info['face'] #检查up主在数据库中是否已经存在 up = Upinfo.query.filter_by(mid=mid).first() if up: userid = up.id else: #存储up主信息 upinfo = Upinfo(mid=mid, username=name, face=face) db.session.add(upinfo) db.session.commit() up = Upinfo.query.filter_by(mid=mid).first() userid = up.id #存储视频信息 video = Videos.query.filter_by(cid=cid).first() if video is None: videos = Videos(cid=cid, title=title, lovenum=like_count, playnum=play_count, addtime=addtime, userid=userid, bvid=bvid, aid=aid) db.session.add(videos) # 添加数据 db.session.commit() # 提交数据 get_bilibili_danmu(cid) get_bilibili_comments(cid, bvid, max_count=20) #爬取弹幕信息 def get_bilibili_danmu(cid): danmu_url = f"https://api.bilibili.com/x/v1/dm/list.so?oid={cid}" danmu_res = requests.get(danmu_url, headers=headers) danmu_res.encoding = 'utf-8' # 解析xml数据 root = ET.fromstring(danmu_res.text) for d in root.iter('d'): # 使用正则表达式去除标点符号和特殊字符 text = re.sub(r"[!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]", "", d.text) # 去除停用词 txt = remove_stopwords(text, stopwords) if txt != "" and len(txt) > 4: # 使用snownlp进行情感分析 s = SnowNLP(d.text) score = "{:.2f}".format(s.sentiments) if s.sentiments > 0.6: level = "正面" elif s.sentiments < 0.4: level = "负面" else: level = "中性" # 判断弹幕是否已经存在 istm = Tanmu.query.filter_by(cid=cid, txt=txt).first() if istm: continue # 将弹幕信息存入数组 dict = {} dict['cid'] = cid dict['txt'] = txt dict['level'] = level dict['score'] = score wordlist.append(dict) # 为Tanmu类属性赋值 tanmu = Tanmu(cid=cid, txt=txt, level=level, score=score) db.session.add(tanmu) # 添加数据 db.session.commit() # 提交数据 def remove_stopwords(text, stopwords): words = text.split() filtered_words = [word for word in words if word not in stopwords] return " ".join(filtered_words) def save_excel(): # 创建一个新的工作簿 wb = Workbook() # 选择默认的工作表 ws = wb.active ws.append(['cID', 'userID', 'txt', 'level', 'score']) # 将弹幕信息存入excel文件 for item in wordlist: # 向excel文件插入一行数据 ws.append([item['cid'], item['userid'], item['txt'], item['level'], item['score']]) # 获取当前时间 cur_time = datetime.now().strftime("%Y%m%d%H%M%S") save_file_name = "tanmu_" + cur_time + ".xlsx" # 保存工作簿到文件 wb.save(save_file_name) wb1 = Workbook() ws1 = wb1.active ws1.append(['cID', 'user', 'content', 'like', 'time', 'level', 'score']) for item in comments: ws1.append(item['cid'], item['username'], item['content'], item['likenum'], item['sendtime'], item['level'], item['score']) save_file_name1 = "comment_" + cur_time + ".xlsx" wb1.save(save_file_name1) def all_characters_same(s): if len(s) == 0: # 先检查字符串是否为空 return True return len(set(s)) == 1 # 将字符串转换为集合,检查长度是否为1 def remove_escape_sequences(text): try: # 解码转义序列 decoded_text = text.encode('latin1').decode('unicode-escape') # 使用emoji库移除emoji return emoji.replace_emoji(decoded_text, replace='') except: return text # 爬取评论 def get_bilibili_comments(cid, video_bvid, max_count=200): """ 获取B站视频评论 :param video_bvid: 视频BV号 :param max_count: 最大获取评论数 :return: 评论列表 """ comments = [] url = f"https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next=0&type=1&oid={video_bvid}&mode=3" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", "Referer": f"https://www.bilibili.com/video/{video_bvid}" } page = 0 while len(comments) < max_count: try: response = requests.get(url, headers=headers) data = response.json() if data['code'] != 0: print(f"获取评论失败: {data['message']}") break replies = data['data']['replies'] if not replies: break for reply in replies: # 检查字符串整个内容是否重复 if all_characters_same(reply['content']['message']) == True: continue comments.append({ 'user': reply['member']['uname'], 'content': reply['content']['message'], 'like': reply['like'], 'time': time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(reply['ctime'])) }) # 情感分析 s = SnowNLP(reply['content']['message']) score = "{:.2f}".format(s.sentiments) if s.sentiments > 0.6: level = "正面" elif s.sentiments < 0.4: level = "负面" else: level = "中性" content = remove_escape_sequences(reply['content']['message']) # 插入数据库 c = Comments(cid=cid, username=reply['member']['uname'], content=content, likenum=reply['like'], sendtime=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(reply['ctime'])), level=level, score=score) db.session.add(c) # 添加数据 db.session.commit() # 提交数据 # 获取下一页评论 if 'cursor' in data['data'] and data['data']['cursor']['is_end'] == False: next_page = data['data']['cursor']['next'] url = f"https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next={next_page}&type=1&oid={video_bvid}&mode=3" page += 1 print(f"正在获取第{page}页评论...") time.sleep(1) # 礼貌性延迟,避免请求过快 else: break except Exception as e: print(f"发生错误: {e}") break # 删除弹幕 @app.route("/deleteTanmu",methods=['POST','GET']) def deleteTanmu(): id = request.args.get("id") tanmu = Tanmu.query.get(id) if not tanmu: return jsonify({"code": 500, "msg": "弹幕记录不存在!"}) db.session.delete(tanmu) db.session.commit() # 插入日志 cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") new_log = Syslog('admin', 'delete', 'deleteTanmu', cur_time) db.session.add(new_log) db.session.commit() return jsonify({"code": 200, "msg": "删除成功"}) # 获取所有评论 @app.route('/showComment', methods=['POST', 'GET']) def showComment(): data = request.get_json() query = data.get("params").get("cid") if query != "": page_objs = Comments.query.filter_by(cid=query).paginate( page=int(data.get("params").get("page", 1)), per_page=int(data.get("params").get("limit", 15)), error_out=False, max_per_page=50 ).items totalcount = Comments.query.filter_by(cid=query).count() else: page_objs = Comments.query.paginate( page=int(data.get("params").get("page", 1)), per_page=int(data.get("params").get("limit", 15)), error_out=False, max_per_page=50 ).items totalcount = Comments.query.count() output = [] for comment in page_objs: video = Videos.query.filter_by(cid=comment.cid).first() comment_data = {} comment_data['id'] = comment.id comment_data['vtitle'] = video.title comment_data['username'] = comment.username comment_data['content'] = comment.content comment_data['likenum'] = comment.likenum comment_data['sendtime'] = comment.sendtime comment_data['level'] = comment.level comment_data['score'] = comment.score output.append(comment_data) # 插入日志 cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") new_log = Syslog('admin', 'query', 'showComment', cur_time) db.session.add(new_log) db.session.commit() # 返回数据 data = {} data['list'] = output data['total'] = totalcount if totalcount == 0: return jsonify({"code": 200, "msg": "无数据", "data": []}) else: return jsonify({"code": 200, "msg": "处理成功", "data": data}) # 删除评论 @app.route("/deleteComment",methods=['POST','GET']) def deleteComment(): id = request.args.get("id") comment = Comments.query.get(id) if not comment: return jsonify({"code": 500, "msg": "评论不存在!"}) db.session.delete(comment) db.session.commit() # 插入日志 cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") new_log = Syslog('admin', 'delete', 'deleteComment', cur_time) db.session.add(new_log) db.session.commit() return jsonify({"code": 200, "msg": "删除成功"}) # 获取所有日志 @app.route('/showSyslog', methods=['POST', 'GET']) def showSyslog(): # 接收查询条件 data = request.get_json() query = data.get("params").get("querydate") if query != "": page_objs = Syslog.query.filter(Syslog.addtime.like('{}%'.format(query))).order_by(Syslog.addtime.desc()).paginate( page=int(data.get("params").get("page", 1)), per_page=int(data.get("params").get("limit", 15)), error_out=False, max_per_page=50 ).items totalcount = Syslog.query.filter(Syslog.addtime.like('{}%'.format(query))).count() else: page_objs = Syslog.query.order_by(Syslog.addtime.desc()).paginate( page=int(data.get("params").get("page", 1)), per_page=int(data.get("params").get("limit", 15)), error_out=False, max_per_page=50 ).items totalcount = Syslog.query.count() output = [] for log in page_objs: log_data = {} log_data['id'] = log.id log_data['username'] = log.username log_data['operation'] = log.operation log_data['method'] = log.method log_data['addtime'] = log.addtime output.append(log_data) # 插入日志 cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") new_log = Syslog('admin', 'query', 'showSyslog', cur_time) db.session.add(new_log) db.session.commit() # 返回数据 data = {} data['list'] = output data['total'] = totalcount if totalcount == 0: return jsonify({"code": 200, "msg": "无数据", "data": []}) else: return jsonify({"code": 200, "msg": "处理成功", "data": data}) # 删除日志 @app.route("/deleteSyslog",methods=['POST','GET']) def deleteSyslog(): id = request.args.get("id") syslog = Syslog.query.get(id) if not syslog: return jsonify({"code": 500, "msg": "日志记录不存在!"}) db.session.delete(syslog) db.session.commit() # 插入日志 cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") new_log = Syslog('admin', 'delete', 'deleteSyslog', cur_time) db.session.add(new_log) db.session.commit() return jsonify({"code": 200, "msg": "删除成功"}) # 获取所有反馈 @app.route('/showFeedback', methods=['POST', 'GET']) def showFeedback(): # 接收查询条件 data = request.get_json() page_objs = Feedbacks.query.order_by(Feedbacks.addtime.desc()).paginate( page=int(data.get("params").get("page", 1)), per_page=int(data.get("params").get("limit", 15)), error_out=False, max_per_page=50 ).items totalcount = Feedbacks.query.count() output = [] for feedback in page_objs: feedback_data = {} feedback_data['id'] = feedback.id feedback_data['username'] = feedback.username feedback_data['phone'] = feedback.phone feedback_data['title'] = feedback.title feedback_data['content'] = feedback.content feedback_data['addtime'] = feedback.addtime output.append(feedback_data) # 插入日志 cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") new_log = Syslog('admin', 'query', 'showFeedback', cur_time) db.session.add(new_log) db.session.commit() # 返回数据 data = {} data['list'] = output data['total'] = totalcount if totalcount == 0: return jsonify({"code": 200, "msg": "无数据", "data": []}) else: return jsonify({"code": 200, "msg": "处理成功", "data": data}) # 删除反馈 @app.route("/deleteFeedback", methods=['POST','GET']) def deleteFeedback(): id = request.args.get("id") feedback = Feedbacks.query.get(id) if not feedback: return jsonify({"code": 500, "msg": "反馈不存在!"}) db.session.delete(feedback) db.session.commit() # 插入日志 cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") new_log = Syslog('admin', 'delete', 'deleteFeedback', cur_time) db.session.add(new_log) db.session.commit() return jsonify({"code": 200, "msg": "删除成功"}) # 发布反馈 @app.route("/sendFeedback", methods=['POST']) def sendFeedback(): data = request.get_json() # 获取JSON数据 username = data.get("username") phone = data.get("phone") title = data.get("title") content = data.get("content") cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") feedback = Feedbacks(title, content, username, phone, cur_time) db.session.add(feedback) db.session.commit() # 插入日志 cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") new_log = Syslog(username, 'add', 'sendFeedback', cur_time) db.session.add(new_log) db.session.commit() return jsonify({"code": 200, "msg": "反馈成功"}) #获取指定用户信息 @app.route('/getUser', methods=['POST','GET']) def getUser(): data = request.get_json() id = data.get("id") user = Users.query.get(int(id)) if not user: return jsonify({'message': '用户不存在!'}) user_data = {} user_data['id'] = user.id user_data['username'] = user.username user_data['password'] = user.password user_data['role'] = user.role user_data['truename'] = user.truename user_data['phone'] = user.phone user_data['sex'] = user.sex if user.headface: user_data['headface'] = "http://localhost:5000/static/uploadfiles/" + user.headface else: user_data['headface'] = "" # 插入日志 cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") new_log = Syslog(user.username, 'query', 'getUser', cur_time) db.session.add(new_log) db.session.commit() return jsonify({"code": 200, "data": user_data}) def allowed_file(filename): """检查文件扩展名是否合法""" return '.' in filename and \ filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS'] # 上传头像 @app.route('/uploadAvatar', methods=['POST']) def uploadAvatar(): # 检查是否有文件被上传 if 'file' not in request.files: return jsonify({'error': 'No file part'}), 400 file = request.files['file'] # 检查是否选择了文件 if file.filename == '': return jsonify({'error': 'No selected file'}), 400 # 检查文件类型和名称 if file and allowed_file(file.filename): # 安全处理文件名 filename = secure_filename(file.filename) # 生成唯一文件名防止冲突 unique_filename = f"{os.urandom(8).hex()}_{filename}" save_path = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename) try: # 保存文件 file.save(save_path) return jsonify({ 'success': True, 'url': unique_filename, 'message': 'File uploaded successfully' }) except Exception as e: return jsonify({'error': str(e)}), 500 else: return jsonify({ 'error': 'File type not allowed', 'allowed_types': list(app.config['ALLOWED_EXTENSIONS']) }), 400 #修改用户信息 @app.route('/updateUser', methods=['POST', 'GET']) def updateUser(): data = request.get_json() id = data.get("id") username = data.get("username") truename = data.get("truename") phone = data.get("phone") sex = data.get("sex") headface = data.get("headface") user = Users.query.filter_by(id=int(id)).first() user.username = username user.truename = truename user.phone = phone user.sex = sex user.headface = headface db.session.commit() # 插入日志 cur_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") new_log = Syslog(user.username, 'update', 'updateUser', cur_time) db.session.add(new_log) db.session.commit() return jsonify({"code": 200, "msg": "更新成功"}) @app.route('/piechart', methods=['POST','GET']) def get_piechart(): data = request.get_json() cid = data.get("cid") positive = 0 neutral = 0 negative = 0 if cid == '': list = db.session.query(Tanmu.level, db.func.count(Tanmu.id)).group_by(Tanmu.level) else: list = db.session.query(Tanmu.level, db.func.count(Tanmu.id)).filter_by(cid=cid).group_by(Tanmu.level) for v in list: if v[0] == '正面': positive = v[1] elif v[0] == '中性': neutral = v[1] else: negative = v[1] data = { "positive": round(positive/(positive+neutral+negative)*100, 2), "neutral": round(neutral/(positive+neutral+negative)*100, 2), "negative": round(negative/(positive+neutral+negative)*100, 2) } return jsonify(data) @app.route('/cpiechart', methods=['POST','GET']) def get_comment_piechart(): data = request.get_json() cid = data.get("cid") positive = 0 neutral = 0 negative = 0 if cid == '': list = db.session.query(Comments.level, db.func.count(Comments.id)).group_by(Comments.level) else: list = db.session.query(Comments.level, db.func.count(Comments.id)).filter_by(cid=cid).group_by(Comments.level) for v in list: if v[0] == '正面': positive = v[1] elif v[0] == '中性': neutral = v[1] else: negative = v[1] data = { "positive": round(positive/(positive+neutral+negative)*100, 2), "neutral": round(neutral/(positive+neutral+negative)*100, 2), "negative": round(negative/(positive+neutral+negative)*100, 2) } return jsonify(data) @app.route('/wordcloud', methods=['POST','GET']) def wordcloud(): data = request.get_json() cid = data.get("cid") if cid == '': tanmus = Tanmu.query.all() comments = Comments.query.all() else: tanmus = Tanmu.query.filter_by(cid=cid).all() comments = Comments.query.filter_by(cid=cid).all() text_list = [] for t in tanmus: text_list.append(t.txt) for c in comments: text_list.append(c.content) # 中文分词处理 text = ' '.join(text_list) words = jieba.cut(text) # 统计词频 word_counts = Counter(words) # 过滤停用词和单个字符 stop_words = {'的', '了', '和', '是', '我', '你', '他', '这', '那', '在', '不'} filtered_words = [ {'name': word, 'value': count} for word, count in word_counts.items() if len(word) > 1 and word not in stop_words ] # 按词频排序并取前100 filtered_words.sort(key=lambda x: x['value'], reverse=True) return jsonify(filtered_words[:100]) @app.route('/barchart', methods=['POST','GET']) def barchart(): videos = [] playnums = [] videolist = Videos.query.order_by(Videos.playnum.desc())[:10] for v in videolist: videos.append(v.bvid) playnums.append(v.playnum) data = { 'categories': videos, 'values': playnums } return jsonify(data) @app.route('/zfchart', methods=['POST','GET']) def zfchart(): data = request.get_json() cid = data.get("cid") text_list = [] if cid == '': tanmus = Tanmu.query.all()[:30] else: tanmus = Tanmu.query.filter_by(cid=cid).all()[:30] for v in tanmus: text_list.append(v.txt) df = pd.DataFrame(text_list) # 将该列中的所有元素强制转换为字符串类型 df = df[0].astype(str) # 对弹幕内容列进行情感分析 sentiment = df.apply(lambda x: SnowNLP(x).sentiments) fig, ax = plt.subplots(figsize=(10, 6), facecolor='#1e1e1e') # 绘制情感得分直方图 ax.hist(sentiment, bins=30, color='skyblue', edgecolor='white', alpha=0.8) # 设置字体,以支持中文 plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文字体为黑体 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 # 设置坐标轴标签和标题(白色) ax.set_title('情感得分直方图', color='white', fontsize=14, pad=20) ax.set_xlabel('得分', color='white', fontsize=14) ax.set_ylabel('数量', color='white', fontsize=14) # 设置坐标轴刻度值为白色 ax.tick_params(axis='both', which='both', colors='white') # 设置坐标轴边框为白色 for spine in ax.spines.values(): spine.set_color('white') spine.set_linewidth(1.5) # 设置边框线宽 # 设置网格线(可选) ax.grid(True, color='white', alpha=0.2, linestyle='--') cur_time = datetime.now().strftime("%Y%m%d%H%M%S") imgname = cur_time + '.png' imgpath = os.path.join('static', 'data', imgname) plt.savefig(imgpath, transparent=True) return jsonify({"imgname": imgname}) if __name__ == '__main__': app.run(port=5000, debug=True, host='0.0.0.0')上述代码中有没有训练模型的代码,如果没有,上面代码是怎么引用的模型,把模型代码提取出来并且解释一下
05-14
""" GitLab Merge Requests 到 Pull Requests 的数据转换 根据mappings.md中的字段映射关系,将GitLab的merge_requests数据转换为标准化的pull_requests格式 """ from typing import Callable, Dict, List, Any, Optional from sqlalchemy import Select, and_, select, Table, MetaData, text from sqlalchemy.sql import quoted_name from ddwh.utils.base_transformer import ( BaseMainReader, BaseConverter, BaseTransformer, BaseRelationReader, ) from ddwh.utils.db_utils import DBUtils from ddwh.utils.db_session import DBSession from ddwh.config import settings from . import parse_proto import uuid class IssueCodeBlocksReader(BaseMainReader): """GitLab Merge Requests 读取器""" def __init__(self, db_utils: DBUtils): super().__init__(db_utils) @property def get_query(self) -> Callable: return self._get_raw_sql def _get_select_query(self) -> Select: metadata = MetaData() table = Table( "issues", metadata, schema="ods_sq", autoload_with=self.db_utils.get_engine_bind(), ) # 创建关联表的Table对象 metrics_table = Table( "components", metadata, schema="ods_sq", autoload_with=self.db_utils.get_engine_bind(), ) return ( select( table.c.id, table.c.title, table.c.description, table.c.state_id, table.c.iid, table.c.source_project_id, table.c.target_project_id, table.c.author_id, table.c.created_at, table.c.merge_commit_sha, table.c.source_branch, table.c.target_branch, table.c.updated_at, table.c._task_id, table.c._tool_id, # 关联merge_request_metrics获取合并和关闭时间 metrics_table.c.merged_at, metrics_table.c.latest_closed_at, # 关联merge_request_diffs获取commit信息 diffs_table.c.base_commit_sha, diffs_table.c.head_commit_sha, # 关联users获取作者信息 users_table.c.name.label("author_name"), ) .select_from( table.outerjoin( metrics_table, (table.c.id == metrics_table.c.merge_request_id) & (table.c._tool_id == metrics_table.c._tool_id), ) .outerjoin( diffs_table, (table.c.id == diffs_table.c.merge_request_id) & (table.c._tool_id == diffs_table.c._tool_id) & (diffs_table.c.diff_type == 2), ) .outerjoin( users_table, (table.c.author_id == users_table.c.id) & (table.c._tool_id == users_table.c._tool_id), ) ) .order_by(table.c.id, table.c._tool_id) ) def _get_raw_sql(self) -> str: # 构建多表关联查询,使用DISTINCT避免重复记录 sql = f""" SELECT DISTINCT ON (iss.kee) iss.kee AS issue_key, com.long_name AS component, iss.message, encode(iss.locations, 'hex') AS locations_hex, iss._task_id, iss._tool_id FROM ods_sq.issues iss LEFT JOIN ods_sq.components com ON iss.component_uuid = com.uuid AND iss._tool_id = com._tool_id ORDER BY iss.kee DESC """ return text(sql) class IssueCodeBlocksConverter(BaseConverter): """GitLab Merge Requests 转换器""" def __init__(self, db_utils: DBUtils): super().__init__(name="issue_code_blocks_converter") self.db_utils = db_utils @property def table_name(self) -> str: return "dwd_fact.issue_code_blocks" @property def upsert_keys(self) -> List[str]: return ["id", "issue_key","_tool_id"] def convert_a_batch(self, data_batch: Dict[str, List]) -> List[Dict[str, Any]]: """转换数据批次 Args: data_batch: 原始数据批次,格式为Dict[str, List] Returns: List[Dict[str, Any]]: 转换后的数据列表 """ converted_records = [] # 获取主表数据 issue_code_blocks = data_batch.get(IssueCodeBlocksReader.__name__, []) for b in issue_code_blocks: try: converted_record = self._convert_issue_code_blocks(b) # 确保总是处理列表类型 if isinstance(converted_record, list): converted_records.extend(converted_record) elif converted_record: # 处理单个字典情况 converted_records.append(converted_record) except Exception as e: self.logger.exception( f"转换issue_code_blocks失败: {b.get('id')}, 错误: {str(e)}" ) continue return converted_records def _convert_issue_code_blocks( self, b: Dict[str, Any], ) -> Optional[Dict[str, Any]]: """转换单个issue记录,提取所有位置组 Args: b: 输入记录 Returns: List[Dict[str, Any]]: 转换后的位置记录列表 (每个位置组生成独立记录) """ # 解析位置信息 location_data = {} hex_str = b.get("locations_hex", "") if hex_str: try: binary_data = bytes.fromhex(hex_str) location_data, _ = parse_proto.parse_to_dict(binary_data) except Exception as e: self.logger.error(f"位置解析失败: {e} | 输入: {hex_str[:50]}...") # 即使解析失败也继续处理 # 收集所有位置组和对应消息 location_groups = [] # 1. 处理顶层位置组 if location_data.get('text_range'): location_groups.append({ "text_range": location_data['text_range'], "msg": location_data.get('msg', '') }) # 2. 处理flow中的嵌套位置组 if location_data.get('flow'): for flow_item in location_data['flow']: # 统一处理location为列表格式 locations = flow_item.get('location', []) if not isinstance(locations, list): locations = [locations] for loc in locations: if loc and loc.get('text_range'): location_groups.append({ "text_range": loc['text_range'], "msg": loc.get('msg', '') }) # 如果没有位置组,创建一条空记录 if not location_groups: location_groups.append({ "text_range": None, "msg": "" }) msg=b.get("message") # 为每个位置组创建记录 records = [] for group in location_groups: tr = group.get('text_range', {}) record = { "id": uuid.uuid4(), "issue_key": b.get("issue_key", ""), "component": b.get("component", ""), "start_line": tr.get("start_line") if tr else None, "end_line": tr.get("end_line") if tr else None, "start_offset": tr.get("start_offset") if tr else None, "end_offset": tr.get("end_offset") if tr else None, "msg": group.get('msg',msg), "_tool_id": b.get("_tool_id", "sonarqube"), "_task_id": settings.task_id, } records.append(record) return records class IssueCodeBlocksTransformer(BaseTransformer): """Pull Requests 转换器""" def __init__(self, db_utils: DBUtils): super().__init__(db_utils) def setup_readers_and_converters(self): """设置读取器和转换器""" # 创建主读取器 issue_code_blocks = IssueCodeBlocksReader(self.db_utils) # 创建转换器 converter = IssueCodeBlocksConverter(self.db_utils) # 注册Reader-Converter配对 self.register_reader_converter_pair(issue_code_blocks, converter) def main(): warehouse_url = settings.warehouse_url session = DBSession(warehouse_url) with session.get_db_utils() as db_utils: # 创建转换器 transformer = IssueCodeBlocksTransformer(db_utils) # 设置读取器和转换器 transformer.setup_readers_and_converters() # 执行数据转换 success = transformer.transform() if success: print("数据转换成功完成") else: print("数据转换失败") if __name__ == "__main__": main() 优先使用位置组的msg ,若没有就用b.get("message")
最新发布
08-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值