From 7ce545fedbfdacdb4d8571563c99d484e512eb7e Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 18 Jun 2026 02:30:42 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/view.py | 16 +- check_sql_structure.py | 69 ------ check_table_rows.py | 19 -- drop_all_tables.py | 31 --- find.py | 163 --------------- fix_fk.py | 67 ------ fix_tixianjilu.py | 122 ----------- import_backup.py | 145 ------------- migrate_data.py | 463 ----------------------------------------- show_tables.py | 13 -- users/views.py | 30 +-- verify_fixes.py | 53 ----- 12 files changed, 23 insertions(+), 1168 deletions(-) delete mode 100644 check_sql_structure.py delete mode 100644 check_table_rows.py delete mode 100644 drop_all_tables.py delete mode 100644 find.py delete mode 100644 fix_fk.py delete mode 100644 fix_tixianjilu.py delete mode 100644 import_backup.py delete mode 100644 migrate_data.py delete mode 100644 show_tables.py delete mode 100644 verify_fixes.py diff --git a/backend/view.py b/backend/view.py index 0b651b0..5a0981b 100644 --- a/backend/view.py +++ b/backend/view.py @@ -3025,7 +3025,7 @@ class GetGuanliDetailView(APIView): # 获取多次分红配置(按次数和会员组织) # 查询该管事的所有多次分红记录 - duoci_records = DuociFenhong.query.filter(UserUID=yonghuid).order_by('cishu') + duoci_records = DuociFenhong.query.filter(yonghuid=yonghuid).order_by('cishu') custom_first = {} # 首次分红定制(cishu=1) extra_map = {} # 其他次数 { cishu: { huiyuan_id: { guanshi_fenhong, jieshao, jiage } } } @@ -3206,7 +3206,7 @@ class UpdateGuanliView(APIView): # 4.2 首次定制分红(cishu=1) if custom_first is not None and isinstance(custom_first, dict): # 获取当前所有首次定制记录 - existing_first = DuociFenhong.query.filter(UserUID=yonghuid, cishu=1) + existing_first = DuociFenhong.query.filter(yonghuid=yonghuid, cishu=1) # 前端传来的定制字典 {会员ID: 金额} for huiyuan_id, amount in custom_first.items(): try: @@ -3215,7 +3215,7 @@ class UpdateGuanliView(APIView): continue if amount <= 0: # 金额为0或负数表示删除定制 - DuociFenhong.query.filter(UserUID=yonghuid, huiyuan=huiyuan_id, cishu=1).delete() + DuociFenhong.query.filter(yonghuid=yonghuid, huiyuan=huiyuan_id, cishu=1).delete() else: DuociFenhong.query.update_or_create( yonghuid=yonghuid, @@ -3266,7 +3266,7 @@ class UpdateGuanliView(APIView): } ) # 删除不在 keep_set 中的额外次数记录 - existing_extra = DuociFenhong.query.filter(UserUID=yonghuid, cishu__gte=2) + existing_extra = DuociFenhong.query.filter(yonghuid=yonghuid, cishu__gte=2) for record in existing_extra: if (record.cishu, record.huiyuan) not in keep_set: record.delete() @@ -3716,7 +3716,7 @@ class GetZuzhangDetailView(APIView): m['zuzhangfc'] = str(m['zuzhangfc']) # 获取多次分红配置(按次数和会员组织) - duoci_records = DuociFenhong.query.filter(UserUID=yonghuid).order_by('cishu') + duoci_records = DuociFenhong.query.filter(yonghuid=yonghuid).order_by('cishu') custom_first = {} # 首次分红定制(cishu=1) extra_map = {} # 其他次数 { cishu: { huiyuan_id: { zuzhang_fenhong, jieshao, jiage } } } @@ -3889,7 +3889,7 @@ class UpdateZuzhangView(APIView): # 4.2 首次定制分红(cishu=1) if custom_first is not None and isinstance(custom_first, dict): - existing_first = DuociFenhong.query.filter(UserUID=yonghuid, cishu=1) + existing_first = DuociFenhong.query.filter(yonghuid=yonghuid, cishu=1) for huiyuan_id, amount in custom_first.items(): try: amount = Decimal(str(amount)) @@ -3897,7 +3897,7 @@ class UpdateZuzhangView(APIView): continue if amount <= 0: # 删除定制(恢复默认) - DuociFenhong.query.filter(UserUID=yonghuid, huiyuan=huiyuan_id, cishu=1).delete() + DuociFenhong.query.filter(yonghuid=yonghuid, huiyuan=huiyuan_id, cishu=1).delete() else: DuociFenhong.query.update_or_create( yonghuid=yonghuid, @@ -3946,7 +3946,7 @@ class UpdateZuzhangView(APIView): } ) # 删除不在 keep_set 中的额外次数记录 - existing_extra = DuociFenhong.query.filter(UserUID=yonghuid, cishu__gte=2) + existing_extra = DuociFenhong.query.filter(yonghuid=yonghuid, cishu__gte=2) for record in existing_extra: if (record.cishu, record.huiyuan) not in keep_set: record.delete() diff --git a/check_sql_structure.py b/check_sql_structure.py deleted file mode 100644 index aa47666..0000000 --- a/check_sql_structure.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python3 -"""检查 user_dashou 中有 user_id 的记录""" -import re - -with open('xaio_cheng_xu_backup.sql', 'r', encoding='utf-8') as f: - content = f.read() - -pattern = re.compile(r"INSERT\s+INTO\s+`user_dashou`\s+VALUES\s*\((.+?)\)\s*;", re.IGNORECASE | re.DOTALL) -matches = list(pattern.finditer(content)) - -# 找有 user_id 的记录 -has_uid = 0 -no_uid = 0 -uid_values = [] -for m in matches: - v = m.group(1).rstrip() - if v.endswith('NULL'): - no_uid += 1 - else: - has_uid += 1 - # 提取最后一个值(user_id) - last_comma = v.rfind(',') - uid_val = v[last_comma+1:].strip() - uid_values.append(uid_val) - -print(f"有 user_id: {has_uid}, 无 user_id: {no_uid}") -print(f"user_id 值样本: {uid_values[:10]}") - -# 检查 user_main 中这些 user_id 是否存在 -# user_main 的 id 字段是 vals[1] -main_pattern = re.compile(r"INSERT\s+INTO\s+`user_main`\s+VALUES\s*\((.+?)\)\s*;", re.IGNORECASE | re.DOTALL) -main_ids = set() -for m in main_pattern.finditer(content): - # 简单提取第二个字段 (id) - v = m.group(1) - # 找前几个逗号 - in_q = False - commas = [] - for i, ch in enumerate(v): - if ch == "'": in_q = not in_q - elif ch == ',' and not in_q: - commas.append(i) - if len(commas) >= 2: break - if len(commas) >= 2: - id_val = v[commas[0]+1:commas[1]].strip() - main_ids.add(id_val) - -print(f"\nuser_main id 范围: {len(main_ids)} 个") -matched = sum(1 for uid in uid_values if uid in main_ids) -print(f"user_dashou user_id 匹配 user_main: {matched}/{len(uid_values)}") - -# 也检查 user_type 分布 -type_pattern = re.compile(r"INSERT\s+INTO\s+`user_main`\s+VALUES\s*\((.+?)\)\s*;", re.IGNORECASE | re.DOTALL) -type_counts = {} -for m in type_pattern.finditer(content): - v = m.group(1) - # 找第12个字段 (user_type, index 11) - in_q = False - commas = [] - for i, ch in enumerate(v): - if ch == "'": in_q = not in_q - elif ch == ',' and not in_q: - commas.append(i) - if len(commas) >= 12: break - if len(commas) >= 12: - type_val = v[commas[10]+1:commas[11]].strip().strip("'") - type_counts[type_val] = type_counts.get(type_val, 0) + 1 - -print(f"\nuser_type 分布: {type_counts}") diff --git a/check_table_rows.py b/check_table_rows.py deleted file mode 100644 index be3a27f..0000000 --- a/check_table_rows.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python3 -"""检查数据库表行数""" -import MySQLdb -from app_secrets import DATABASE_HOST, DATABASE_PORT, DATABASE_USER, DATABASE_PASSWORD, DATABASE_NAME - -conn = MySQLdb.connect( - host=DATABASE_HOST, port=int(DATABASE_PORT), - user=DATABASE_USER, password=DATABASE_PASSWORD, - database=DATABASE_NAME -) -cursor = conn.cursor() -cursor.execute( - "SELECT TABLE_NAME, TABLE_ROWS FROM information_schema.TABLES " - "WHERE TABLE_SCHEMA = %s ORDER BY TABLE_NAME", - [DATABASE_NAME] -) -for row in cursor.fetchall(): - print(f"{row[0]:40s} {row[1]}") -conn.close() diff --git a/drop_all_tables.py b/drop_all_tables.py deleted file mode 100644 index bcbaff4..0000000 --- a/drop_all_tables.py +++ /dev/null @@ -1,31 +0,0 @@ -import MySQLdb - -conn = MySQLdb.connect( - host='gvsds.com', port=50030, user='root', - password='sajksh.sdfGH3YUge.wjkd+', - database='xaio_cheng_xu', charset='utf8mb4' -) -cur = conn.cursor() - -# 获取所有表 -cur.execute("SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA='xaio_cheng_xu'") -tables = [row[0] for row in cur.fetchall()] -print(f'共 {len(tables)} 张表') - -# 禁用外键检查,删除所有表 -cur.execute('SET FOREIGN_KEY_CHECKS = 0') -for t in tables: - cur.execute(f'DROP TABLE IF EXISTS `{t}`') - print(f' 已删除: {t}') -cur.execute('SET FOREIGN_KEY_CHECKS = 1') - -conn.commit() -print(f'\n已删除全部 {len(tables)} 张表') - -# 验证 -cur.execute("SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='xaio_cheng_xu'") -count = cur.fetchone()[0] -print(f'剩余表数: {count}') - -cur.close() -conn.close() diff --git a/find.py b/find.py deleted file mode 100644 index 487974e..0000000 --- a/find.py +++ /dev/null @@ -1,163 +0,0 @@ -""" -REPL 模式文件内容搜索工具 -支持正则或纯文本搜索,默认搜索当前目录 -""" -import os -import re -import sys - -# 硬编码排除目录 -EXCLUDE_DIRS = { - '.git', '.vs', 'node_modules', '__pycache__', '.idea', - 'miniprogram_npm', '_backup_pre_redesign', -} - -# 排除的文件扩展名 -EXCLUDE_EXTS = { - '.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico', '.bmp', - '.mp3', '.mp4', '.wav', '.avi', - '.zip', '.rar', '.7z', '.tar', '.gz', - '.exe', '.dll', '.so', '.dylib', - '.pyc', '.pyo', '.class', '.o', '.obj', - '.db', '.sqlite', '.vsidx', -} - -# 默认搜索根目录 -DEFAULT_ROOT = os.path.dirname(os.path.abspath(__file__)) - - -def should_skip(dirpath): - """判断目录是否应跳过""" - parts = dirpath.replace('\\', '/').split('/') - return any(p in EXCLUDE_DIRS for p in parts) - - -def search(pattern, root=DEFAULT_ROOT, use_regex=True, max_results=50): - """搜索文件内容""" - try: - if use_regex: - compiled = re.compile(pattern, re.IGNORECASE) - except re.error as e: - print(f' 正则语法错误: {e}') - return - - count = 0 - for dirpath, dirnames, filenames in os.walk(root): - # 就地修改 dirnames 以跳过排除目录 - dirnames[:] = [d for d in dirnames if d not in EXCLUDE_DIRS] - - for fname in filenames: - ext = os.path.splitext(fname)[1].lower() - if ext in EXCLUDE_EXTS: - continue - - fpath = os.path.join(dirpath, fname) - relpath = os.path.relpath(fpath, root) - try: - with open(fpath, 'r', encoding='utf-8', errors='ignore') as f: - for lineno, line in enumerate(f, 1): - line_stripped = line.rstrip('\n\r') - if use_regex: - match = compiled.search(line_stripped) - if match: - highlight = line_stripped[:match.start()] + \ - f'>>> {match.group()} <<<' + \ - line_stripped[match.end():] - print(f' {relpath}:{lineno} {highlight}') - count += 1 - else: - if pattern.lower() in line_stripped.lower(): - print(f' {relpath}:{lineno} {line_stripped}') - count += 1 - - if count >= max_results: - print(f'\n ... 已达上限 {max_results} 条,停止') - return - except (PermissionError, OSError): - continue - - if count == 0: - print(' 未找到匹配内容') - else: - print(f'\n 共 {count} 条匹配') - - -def main(): - print('=== 文件内容搜索工具 ===') - print(f'搜索根目录: {DEFAULT_ROOT}') - print(f'排除目录: {EXCLUDE_DIRS}') - print() - print('命令:') - print(' /regex 正则搜索') - print(' /text 纯文本搜索') - print(' /max 设置结果上限(默认50)') - print(' /dir 切换搜索目录') - print(' /help 显示帮助') - print(' /quit 退出') - print() - print('直接输入内容默认使用正则搜索') - print() - - root = DEFAULT_ROOT - use_regex = True - max_results = 50 - - while True: - try: - raw = input('find> ').strip() - except (EOFError, KeyboardInterrupt): - print('\n再见') - break - - if not raw: - continue - - if raw == '/quit': - print('再见') - break - - if raw == '/help': - print(' /regex 正则搜索') - print(' /text 纯文本搜索') - print(' /max 设置结果上限') - print(' /dir 切换搜索目录') - print(' /help 显示帮助') - print(' /quit 退出') - print(' 直接输入内容默认使用正则搜索') - continue - - if raw.startswith('/regex '): - pattern = raw[7:].strip() - if pattern: - search(pattern, root, use_regex=True, max_results=max_results) - continue - - if raw.startswith('/text '): - pattern = raw[6:].strip() - if pattern: - search(pattern, root, use_regex=False, max_results=max_results) - continue - - if raw.startswith('/max '): - try: - max_results = int(raw[5:].strip()) - print(f' 结果上限设为 {max_results}') - except ValueError: - print(' 请输入数字') - continue - - if raw.startswith('/dir '): - new_dir = raw[5:].strip() - if os.path.isdir(new_dir): - root = os.path.abspath(new_dir) - print(f' 搜索目录切换为: {root}') - else: - print(f' 目录不存在: {new_dir}') - continue - - # 默认正则搜索 - search(raw, root, use_regex=use_regex, max_results=max_results) - - -if __name__ == '__main__': - main() diff --git a/fix_fk.py b/fix_fk.py deleted file mode 100644 index ef7b887..0000000 --- a/fix_fk.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python3 -"""修复 yonghu_dianpu_bangding 表的 FK 约束""" -import MySQLdb -from app_secrets import DATABASE_HOST, DATABASE_PORT, DATABASE_USER, DATABASE_PASSWORD, DATABASE_NAME - -conn = MySQLdb.connect( - host=DATABASE_HOST, port=int(DATABASE_PORT), - user=DATABASE_USER, password=DATABASE_PASSWORD, - database=DATABASE_NAME, charset='utf8mb4' -) -cursor = conn.cursor() - -# 1. 查看所有引用 User 表的 FK 约束 -cursor.execute(""" - SELECT CONSTRAINT_NAME, TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME - FROM information_schema.KEY_COLUMN_USAGE - WHERE TABLE_SCHEMA = %s AND REFERENCED_TABLE_NAME = 'User' -""", [DATABASE_NAME]) - -fks = cursor.fetchall() -print("引用 User 表的 FK 约束:") -for fk in fks: - print(f" {fk[0]}: {fk[1]}.{fk[2]} -> {fk[3]}.{fk[4]}") - -# 2. 删除所有引用 User.UserUID 的 FK 约束(类型不兼容的) -for fk in fks: - if fk[4] == 'UserUID': # 引用了 UserUID (varchar) 而不是 UserUUID (binary) - constraint_name = fk[0] - table_name = fk[1] - print(f"\n删除不兼容 FK: {constraint_name} on {table_name}") - try: - cursor.execute(f"ALTER TABLE `{table_name}` DROP FOREIGN KEY `{constraint_name}`") - conn.commit() - print(f" 已删除 {constraint_name}") - except Exception as e: - print(f" 删除失败: {e}") - -# 3. 修改 yonghu_dianpu_bangding.UserUUID 列类型 -print("\n修改 yonghu_dianpu_bangding.UserUUID 列类型...") -try: - cursor.execute("ALTER TABLE yonghu_dianpu_bangding MODIFY COLUMN UserUUID binary(16) NOT NULL") - conn.commit() - print(" 修改成功") -except Exception as e: - print(f" 修改失败: {e}") - -# 4. 重新添加 FK 约束 -print("\n重新添加 FK 约束...") -try: - cursor.execute(""" - ALTER TABLE yonghu_dianpu_bangding - ADD CONSTRAINT yonghu_dianpu_bangding_UserUUID_fk - FOREIGN KEY (UserUUID) REFERENCES User(UserUUID) - """) - conn.commit() - print(" FK 约束添加成功") -except Exception as e: - print(f" FK 约束添加失败: {e}") - -# 5. 验证 -print("\n验证表结构:") -cursor.execute("DESCRIBE yonghu_dianpu_bangding") -for row in cursor.fetchall(): - print(f" {row}") - -conn.close() -print("\n完成!") diff --git a/fix_tixianjilu.py b/fix_tixianjilu.py deleted file mode 100644 index eacf80f..0000000 --- a/fix_tixianjilu.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python3 -"""修复 tixianjilu 导入 — 使用指定列名的 INSERT""" -import re, sys, time, MySQLdb - -sys.path.insert(0, '.') -import os; os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'a_long_dianjing.settings') -import django; django.setup() -from app_secrets import DATABASE_HOST, DATABASE_PORT, DATABASE_USER, DATABASE_PASSWORD, DATABASE_NAME - -SQL_FILE = os.path.join(os.path.dirname(__file__), 'xaio_cheng_xu_backup.sql') - -with open(SQL_FILE, 'r', encoding='utf-8') as f: - sql_content = f.read() - -# 旧表字段顺序(SQL INSERT VALUES 的顺序) -OLD_COLUMNS = [ - 'id', 'yonghuid', 'avatar', 'phone', 'nicheng', 'leixing', 'zhifu', - 'skzhanghao', 'jine', 'zhuangtai', 'fangshi', 'shenheid', 'bhliyou', - 'create_time', 'update_time', 'shenhe_danhao', 'shenhe_jilu_id' -] - -# 新表字段顺序 -NEW_COLUMNS = [ - 'id', 'yonghuid', 'avatar', 'phone', 'nicheng', 'leixing', 'zhifu', - 'skzhanghao', 'jine', 'zhuangtai', 'fangshi', 'shenheid', 'bhliyou', - 'shenhe_jilu_id', 'shenhe_danhao', 'create_time', 'update_time' -] - -def parse_sql_value(val_str): - val_str = val_str.strip() - if val_str.upper() == 'NULL': return None - if val_str.startswith("'") and val_str.endswith("'"): - return val_str[1:-1].replace("\\'", "'").replace("\\\\", "\\") - try: return int(val_str) - except ValueError: - try: return float(val_str) - except ValueError: return val_str - -def split_sql_values(values_str): - values, current, in_quote, escape = [], [], False, False - for ch in values_str: - if escape: current.append(ch); escape = False; continue - if ch == '\\': current.append(ch); escape = True; continue - if ch == "'": in_quote = not in_quote; current.append(ch); continue - if ch == ',' and not in_quote: values.append(''.join(current).strip()); current = []; continue - current.append(ch) - if current: values.append(''.join(current).strip()) - return [parse_sql_value(v) for v in values] - -pattern = re.compile(r"INSERT\s+INTO\s+`tixianjilu`\s+VALUES\s*\((.+?)\)\s*;", re.IGNORECASE | re.DOTALL) -matches = list(pattern.finditer(sql_content)) -print(f"找到 {len(matches)} 条 tixianjilu 记录") - -conn = MySQLdb.connect( - host=DATABASE_HOST, port=int(DATABASE_PORT), - user=DATABASE_USER, password=DATABASE_PASSWORD, - database=DATABASE_NAME, charset='utf8mb4', - connect_timeout=10, read_timeout=60, write_timeout=60 -) -cursor = conn.cursor() -cursor.execute('SET FOREIGN_KEY_CHECKS = 0') - -success = 0 -fail = 0 -start = time.time() - -for i, m in enumerate(matches): - vals = split_sql_values(m.group(1)) - if len(vals) != len(OLD_COLUMNS): - fail += 1 - continue - - # 旧字段 → 值映射 - old_dict = dict(zip(OLD_COLUMNS, vals)) - - # 按新字段顺序构建值列表 - new_vals = [] - for col in NEW_COLUMNS: - new_vals.append(old_dict.get(col)) - - # 构建 INSERT 语句(指定列名) - col_names = ', '.join(f'`{c}`' for c in NEW_COLUMNS) - val_parts = [] - for v in new_vals: - if v is None: - val_parts.append('NULL') - elif isinstance(v, str): - escaped = conn.escape_string(v) - if isinstance(escaped, bytes): escaped = escaped.decode() - val_parts.append(f"'{escaped}'") - elif isinstance(v, bool): - val_parts.append('1' if v else '0') - elif isinstance(v, (int, float)): - val_parts.append(str(v)) - else: - val_parts.append('NULL') - - sql = f"INSERT INTO `tixianjilu` ({col_names}) VALUES ({', '.join(val_parts)})" - try: - cursor.execute(sql) - success += 1 - except Exception as e: - fail += 1 - if fail <= 3: - print(f" ERR: {str(e)[:100]}") - - if success % 100 == 0 and success > 0: - conn.commit() - - if (i + 1) % 200 == 0: - elapsed = time.time() - start - pct = (i + 1) / len(matches) - sys.stdout.write(f'\r [{pct:5.1%}] {i+1}/{len(matches)} {elapsed:.0f}s OK:{success} FAIL:{fail}') - sys.stdout.flush() - -conn.commit() -cursor.execute('SET FOREIGN_KEY_CHECKS = 1') -conn.commit() -conn.close() - -elapsed = time.time() - start -print(f'\n完成: 成功 {success}, 失败 {fail}, 耗时 {elapsed:.0f}s') diff --git a/import_backup.py b/import_backup.py deleted file mode 100644 index bc4c6b9..0000000 --- a/import_backup.py +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env python3 -"""只导入用户迁移所需的表到临时数据库 xaio_old""" -import MySQLdb -import re -from app_secrets import DATABASE_HOST, DATABASE_PORT, DATABASE_USER, DATABASE_PASSWORD - -# 需要导入的表(用户相关) -NEEDED_TABLES = { - 'user_main', 'user_dashou', 'user_guanshi', 'user_kefu', - 'user_shangjia', 'user_boss', 'admin_profile', 'user_zuzhang', - 'user_shenheguan', 'user_role', 'role', 'permission', - 'role_permission', 'account_permission', -} - -def get_conn(db=None): - kwargs = dict( - host=DATABASE_HOST, port=int(DATABASE_PORT), - user=DATABASE_USER, password=DATABASE_PASSWORD, - charset='utf8mb4', connect_timeout=60, - read_timeout=300, write_timeout=300, - ) - if db: - kwargs['database'] = db - return MySQLdb.connect(**kwargs) - -# Drop and recreate -conn = get_conn() -cursor = conn.cursor() -cursor.execute('DROP DATABASE IF EXISTS xaio_old') -cursor.execute('CREATE DATABASE xaio_old CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci') -conn.commit() -conn.close() -print('临时数据库 xaio_old 已重建') - -# Read the SQL file -with open('xaio_cheng_xu_backup.sql', 'r', encoding='utf-8') as f: - sql_content = f.read() - -# Parse and filter statements -# We need CREATE TABLE and INSERT statements for NEEDED_TABLES only -# Also need DROP TABLE IF EXISTS for those tables -statements = [] -current = [] -current_table = None -in_create = False - -for line in sql_content.split('\n'): - stripped = line.strip() - if not stripped or stripped.startswith('--') or stripped.startswith('/*'): - continue - - # Detect table name from CREATE TABLE or DROP TABLE or INSERT INTO - create_match = re.match(r'CREATE\s+TABLE\s+`(\w+)`', stripped, re.IGNORECASE) - drop_match = re.match(r'DROP\s+TABLE\s+IF\s+EXISTS\s+`(\w+)`', stripped, re.IGNORECASE) - insert_match = re.match(r'INSERT\s+INTO\s+`(\w+)`', stripped, re.IGNORECASE) - - if create_match: - current_table = create_match.group(1) - in_create = True - elif drop_match: - current_table = drop_match.group(1) - elif insert_match: - current_table = insert_match.group(1) - in_create = False - - # Only include statements for needed tables - if current_table and current_table in NEEDED_TABLES: - current.append(line) - - if stripped.endswith(';'): - stmt = '\n'.join(current).strip() - current = [] - current_table = None - in_create = False - upper = stmt.upper() - if not upper.startswith('SET ') and not upper.startswith('USE '): - statements.append(stmt) - elif stripped.endswith(';'): - # Not a needed table, skip - current = [] - current_table = None - in_create = False - elif current_table and current_table in NEEDED_TABLES: - current.append(line) - else: - # Not needed, skip but track state - if stripped.endswith(';'): - current = [] - current_table = None - -print(f'筛选出 {len(statements)} 条用户相关SQL语句') - -# Execute -conn = get_conn(db='xaio_old') -cursor = conn.cursor() -cursor.execute('SET FOREIGN_KEY_CHECKS = 0') -executed = 0 -errors = 0 - -for stmt in statements: - try: - cursor.execute(stmt) - executed += 1 - if executed % 20 == 0: - conn.commit() - except MySQLdb.OperationalError as e: - if e.args[0] in (2006, 2013): - try: - conn.close() - except: - pass - conn = get_conn(db='xaio_old') - cursor = conn.cursor() - try: - cursor.execute(stmt) - executed += 1 - except Exception as e2: - errors += 1 - if errors <= 5: - print(f' ERR(retry): {str(e2)[:100]}') - else: - errors += 1 - if errors <= 5: - print(f' ERR: {str(e)[:100]}') - except Exception as e: - errors += 1 - if errors <= 5: - print(f' ERR: {str(e)[:100]}') - -conn.commit() -cursor.execute('SET FOREIGN_KEY_CHECKS = 1') -conn.commit() -print(f'\n导入完成: 成功 {executed}, 错误 {errors}') - -# Check row counts -print('\n关键表行数:') -for table in sorted(NEEDED_TABLES): - try: - cursor.execute('SELECT COUNT(*) FROM `%s`' % table) - count = cursor.fetchone()[0] - print(f' {table}: {count} rows') - except Exception: - print(f' {table}: NOT FOUND') - -conn.close() diff --git a/migrate_data.py b/migrate_data.py deleted file mode 100644 index 692bead..0000000 --- a/migrate_data.py +++ /dev/null @@ -1,463 +0,0 @@ -#!/usr/bin/env python3 -""" -migrate_data.py — 从 SQL 备份文件直接迁移数据到新的 gvsdsdk User + RBAC 体系 -v3: 正确的字段映射 + 基于扩展表存在性分配角色 + bulk_create + 实时进度 -""" -import os, sys, re, uuid, time, datetime, MySQLdb - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'a_long_dianjing.settings') -import django; django.setup() - -from app_secrets import DATABASE_HOST, DATABASE_PORT, DATABASE_USER, DATABASE_PASSWORD, DATABASE_NAME - -TENANT_UUID = uuid.UUID('a0000000-0000-0000-0000-000000000001').bytes -COMPANY_UUID = uuid.UUID('b0000000-0000-0000-0000-000000000001').bytes -BATCH_SIZE = 500 - -ROLE_MAP = { - 'normal': '消费者', 'dashou': '打手', 'shop': '商家', - 'guanshi': '负责人', 'admin': '管理员', 'kefu': '客服', - 'zuzhang': '组长', 'shenheguan': '审核官', -} - -# 角色优先级(高→低): 管理员 > 客服 > 负责人 > 组长 > 审核官 > 商家 > 打手 > 消费者 -ROLE_PRIORITY = ['admin', 'kefu', 'guanshi', 'zuzhang', 'shenheguan', 'shop', 'dashou', 'normal'] - -# 扩展表 → 角色类型 映射 -EXT_ROLE_MAP = { - 'admin_profile': 'admin', - 'user_kefu': 'kefu', - 'user_guanshi': 'guanshi', - 'user_zuzhang': 'zuzhang', - 'user_shenheguan': 'shenheguan', - 'user_shangjia': 'shop', - 'user_dashou': 'dashou', -} - -SQL_FILE = os.path.join(os.path.dirname(__file__), 'xaio_cheng_xu_backup.sql') - - -class Progress: - def __init__(self, total, width=35): - self.total = total; self.width = width; self.start = time.time(); self.done = 0 - def update(self, n=1): - self.done += n; pct = self.done / self.total if self.total else 0 - filled = int(self.width * pct); bar = '█' * filled + '░' * (self.width - filled) - elapsed = time.time() - self.start - eta = (elapsed / self.done * (self.total - self.done)) if self.done else 0 - sys.stdout.write(f'\r [{bar}] {pct:5.1%} {self.done}/{self.total} {elapsed:.0f}s ETA{eta:.0f}s') - sys.stdout.flush() - def finish(self): - elapsed = time.time() - self.start - sys.stdout.write(f'\r [{"█"*self.width}] 100% {self.done}/{self.total} {elapsed:.0f}s\n') - sys.stdout.flush() - - -def parse_insert_values(table_name, sql_content): - pattern = re.compile(r"INSERT\s+INTO\s+`" + re.escape(table_name) + r"`\s+VALUES\s*\((.+?)\)\s*;", re.IGNORECASE | re.DOTALL) - return [m.group(1) for m in pattern.finditer(sql_content)] - - -def parse_sql_value(val_str): - val_str = val_str.strip() - if val_str.upper() == 'NULL': return None - if val_str.startswith("'") and val_str.endswith("'"): - return val_str[1:-1].replace("\\'", "'").replace("\\\\", "\\") - try: return int(val_str) - except ValueError: - try: return float(val_str) - except ValueError: return val_str - - -def split_sql_values(values_str): - values, current, in_quote, escape = [], [], False, False - for ch in values_str: - if escape: current.append(ch); escape = False; continue - if ch == '\\': current.append(ch); escape = True; continue - if ch == "'": in_quote = not in_quote; current.append(ch); continue - if ch == ',' and not in_quote: values.append(''.join(current).strip()); current = []; continue - current.append(ch) - if current: values.append(''.join(current).strip()) - return [parse_sql_value(v) for v in values] - - -def parse_dt(v): - if isinstance(v, str) and v: - try: return datetime.datetime.fromisoformat(v.replace(' ', 'T')) - except: pass - return datetime.datetime.utcnow() - - -def get_raw_conn(db=None): - kwargs = dict(host=DATABASE_HOST, port=int(DATABASE_PORT), user=DATABASE_USER, - password=DATABASE_PASSWORD, charset='utf8mb4', connect_timeout=10, - read_timeout=60, write_timeout=60) - if db: kwargs['database'] = db - return MySQLdb.connect(**kwargs) - - -def run_migration(): - from gvsdsdk.models import User, Role, UserRole - from users.models import ( - UserBoss, UserDashou, UserShangjia, UserGuanshi, - UserZuzhang, UserShenheguan, AdminProfile, UserKefu, - UserSensitiveData - ) - - print("=" * 60) - print("开始从 SQL 备份迁移数据到 gvsdsdk.User + RBAC") - print("=" * 60) - - # [0] 读取 SQL - print("\n[0/7] 读取 SQL 备份文件...", end=' ') - with open(SQL_FILE, 'r', encoding='utf-8') as f: - sql_content = f.read() - print(f"{len(sql_content)/1024/1024:.1f} MB") - - # [1] 解析所有扩展表的 user_id → 建立角色映射 - print("\n[1/7] 解析扩展表建立角色映射...") - - # 正确的 user_id 索引位置 - ext_user_id_idx = { - 'user_dashou': 22, - 'user_guanshi': 11, - 'user_kefu': 9, - 'user_shangjia': 14, - 'user_boss': 6, - 'admin_profile': 4, - 'user_zuzhang': 17, - 'user_shenheguan': 9, - } - - # user_main.id → 角色集合 - user_roles = {} # old_user_id -> set of role_types - - for table_name, role_type in EXT_ROLE_MAP.items(): - inserts = parse_insert_values(table_name, sql_content) - uid_idx = ext_user_id_idx[table_name] - count = 0 - for values_str in inserts: - vals = split_sql_values(values_str) - if uid_idx < len(vals) and vals[uid_idx] is not None: - old_uid = vals[uid_idx] - if old_uid not in user_roles: - user_roles[old_uid] = set() - user_roles[old_uid].add(role_type) - count += 1 - print(f" {table_name}: {count} 条有 user_id") - - # [2] 解析 user_main - print("\n[2/7] 解析 user_main...") - user_main_inserts = parse_insert_values('user_main', sql_content) - total = len(user_main_inserts) - print(f" 共 {total} 条记录") - - uid_map = {} # yonghuid -> UserUUID (bytes) - user_id_map = {} # old id -> yonghuid - phone_to_yonghuid = {} - - # 先解析所有 user_main 记录 - user_data = [] # (old_id, yonghuid, fields_dict, role_type) - prog = Progress(total) - - for i, values_str in enumerate(user_main_inserts): - vals = split_sql_values(values_str) - if len(vals) < 16: - prog.update(); continue - - old_id = vals[1] - yonghuid = str(vals[2]) if vals[2] else None - if not yonghuid: - prog.update(); continue - - # 确定角色:基于扩展表存在性 + user_type - roles = user_roles.get(old_id, set()) - user_type = str(vals[11]) if vals[11] else 'normal' - - # user_type 也可能指定角色 - if user_type == 'admin': - roles.add('admin') - elif user_type == 'kefu': - roles.add('kefu') - - # 如果没有任何角色,默认为 normal - if not roles: - roles.add('normal') - - # 选择优先级最高的角色 - primary_role = 'normal' - for r in ROLE_PRIORITY: - if r in roles: - primary_role = r - break - - user_data.append((old_id, yonghuid, vals, primary_role, roles)) - user_id_map[old_id] = yonghuid - phone = str(vals[5]) if vals[5] else '' - if phone: phone_to_yonghuid[phone] = yonghuid - prog.update() - - prog.finish() - print(f" 解析完成: {len(user_data)} 条有效记录") - - # [3] 创建角色 - print("\n[3/7] 创建角色...") - created_roles = {} - for user_type, role_name in ROLE_MAP.items(): - role, created = Role.objects.get_or_create( - RoleName=role_name, TenantUUID=TENANT_UUID, - defaults={'RoleUUID': uuid.uuid4().bytes, 'RoleDesc': f'{role_name}角色', 'RoleStatus': 1, 'AssignScope': 0}) - created_roles[user_type] = role - print(f" {role_name}: {'NEW' if created else 'EXISTS'}") - - # [4] 批量创建 User + UserRole + UserSensitiveData - print("\n[4/7] 批量创建 User + UserRole + UserSensitiveData...") - - user_batch, ur_batch, usd_batch = [], [], [] - errors = 0 - prog = Progress(len(user_data)) - - for old_id, yonghuid, vals, primary_role, all_roles in user_data: - openid = str(vals[3]) if vals[3] else '' - avatar = str(vals[4]) if vals[4] else 'a_long/morentouxiang.jpg' - phone = str(vals[5]) if vals[5] else '' - password = str(vals[6]) if vals[6] else '' - zhifu = str(vals[7]) if vals[7] else '' - skzhanghao = str(vals[8]) if vals[8] else '' - ip = str(vals[9]) if vals[9] else '' - last_login_time = vals[10] - create_time = vals[12] - unionid = str(vals[14]) if vals[14] else '' - shoujihao_renzheng = bool(vals[15]) if vals[15] is not None else False - - user_uuid = uuid.uuid4().bytes - ct, lt = parse_dt(create_time), parse_dt(last_login_time) - - user_batch.append(User( - UserUUID=user_uuid, UserName=yonghuid, UserUID=yonghuid, - OpenID=openid, UnionID=unionid, Avatar=avatar, Phone=phone, - PhoneVerified=shoujihao_renzheng, IP=ip, UserAccountLicense=1, - UserPositionStatus=0, UserCreateTime=ct, UserLastLoginDate=lt, - IsStaff=('admin' in all_roles), IsSuperuser=('admin' in all_roles))) - - # 为每个角色创建 UserRole(多对多) - for role_type in all_roles: - role = created_roles.get(role_type) - if role: - ur_batch.append(UserRole( - UserRoleUUID=uuid.uuid4().bytes, UserUUID=user_uuid, - RoleUUID=role.RoleUUID, CompanyUUID=COMPANY_UUID)) - - usd_batch.append(UserSensitiveData( - user_uuid_id=user_uuid, password=password, zhifu=zhifu, - skzhanghao=skzhanghao, shoujihao_renzheng=shoujihao_renzheng)) - - uid_map[yonghuid] = user_uuid - - if len(user_batch) >= BATCH_SIZE: - try: - User.objects.bulk_create(user_batch, ignore_conflicts=True) - UserRole.objects.bulk_create(ur_batch, ignore_conflicts=True) - UserSensitiveData.objects.bulk_create(usd_batch, ignore_conflicts=True) - except Exception: errors += len(user_batch) - user_batch, ur_batch, usd_batch = [], [], [] - prog.update() - - if user_batch: - try: - User.objects.bulk_create(user_batch, ignore_conflicts=True) - UserRole.objects.bulk_create(ur_batch, ignore_conflicts=True) - UserSensitiveData.objects.bulk_create(usd_batch, ignore_conflicts=True) - except Exception: errors += len(user_batch) - - prog.finish() - print(f" 成功: {len(uid_map)}, 错误: {errors}") - - # [5] 迁移扩展表 — 用 ORM bulk_create(正确字段映射) - print("\n[5/7] 迁移扩展表...") - - # 正确的字段映射: (sql_index, model_field_name) - # None = 跳过, '_user_id' = FK 到新 User - ext_configs = [ - ('user_dashou', UserDashou, [ - (0, None), (1, 'nicheng'), (2, 'chenghao'), (3, 'zhuangtai'), (4, 'zaixianzhuangtai'), - (5, 'zhanghaozhuangtai'), (6, 'jieshao'), (7, 'jiedanzongliang'), (8, 'chengjiaozongliang'), - (9, 'tuikuanliang'), (10, 'yue'), (11, 'zonge'), (12, 'dianhua'), (13, 'wechat'), - (14, 'yaoqingren'), (15, 'jinrijiedan'), (16, 'jinrishouyi'), (17, 'jinyuejiedan'), - (18, 'jinyueshouyi'), (19, 'jifen'), (20, 'yajin'), (21, None), # create_time - (22, '_user_id'), # user_id FK - (23, 'ewai_xiane'), (24, 'jinritixian_jine'), (25, 'kaioi_ewai_xiane'), - (26, 'last_tixian_date'), - ]), - ('user_guanshi', UserGuanshi, [ - (0, None), (1, 'yaoqingma'), (2, 'dianhua'), (3, 'wechat'), - (4, 'yaogingshuliang'), (5, 'zhuangtai'), (6, 'jinrichongzhi'), - (7, 'jinyuechongzhi'), (8, 'chongzhifenrun'), (9, 'yue'), (10, None), # create_time - (11, '_user_id'), - (12, 'fenghong_erci'), (13, 'fenghong_erci_enabled'), (14, 'fenhong_yici'), - (15, 'ewai_xiane'), (16, 'jinritixian_jine'), (17, 'kaioi_ewai_xiane'), - (18, 'last_tixian_date'), (19, 'yaoqingren'), (20, 'invite_qrcode_url'), - ]), - ('user_kefu', UserKefu, [ - (0, None), (1, 'nicheng'), (2, 'erjimima'), (3, 'zhuangtai'), - (4, 'jinrichuli'), (5, 'jinyuechuli'), (6, 'zongchuli'), - (7, None), (8, None), (9, '_user_id'), - ]), - ('user_shangjia', UserShangjia, [ - (0, None), (1, 'nicheng'), (2, 'zhuangtai'), (3, 'dianhua'), (4, 'wechat'), - (5, 'fabu'), (6, 'tuikuan'), (7, 'yue'), (8, 'chengjiao'), - (9, 'jinridingdan'), (10, 'jinriliushui'), (11, 'jinyuedingdan'), - (12, 'jinyueliushui'), (13, None), (14, '_user_id'), - ]), - ('user_boss', UserBoss, [ - (0, None), (1, 'nickname'), (2, 'zonge'), (3, 'alldingdan'), - (4, 'alltui'), (5, None), (6, '_user_id'), - ]), - ('admin_profile', AdminProfile, [ - (0, None), (1, 'password'), (2, 'wechat'), (3, None), - (4, '_user_id'), (5, 'yaoqingma'), - ]), - ('user_zuzhang', UserZuzhang, [ - (0, None), (1, 'yaoqingma'), (2, 'fenyong_zonge'), (3, 'ketixian_jine'), - (4, 'yaoqing_zongshu'), (5, 'jinri_fenyong'), (6, 'jinyue_fenyong'), - (7, 'zhuangtai'), (8, 'haibao_url'), (9, 'jinri_tixian'), (10, 'last_tixian_time'), - (11, 'ewai_tixian_xiane'), (12, 'kaioi_ewai_tixian'), (13, 'kaioi_ewai_fenhong'), - (14, 'ewai_fenhong_jine'), (15, None), (16, None), (17, '_user_id'), - ]), - ('user_shenheguan', UserShenheguan, [ - (0, None), (1, 'zhuangtai'), (2, 'shenhe_zhuangtai'), - (3, 'shenhe_zongshu'), (4, 'tongguo_zongshu'), (5, 'yue'), (6, 'zonge'), - (7, None), (8, None), (9, '_user_id'), (10, 'is_renzheng'), - ]), - ] - - for table_name, model, field_map in ext_configs: - inserts = parse_insert_values(table_name, sql_content) - if not inserts: - print(f" {table_name}: 0 条"); continue - - user_id_sql_idx = next((idx for idx, fn in field_map if fn == '_user_id'), None) - if user_id_sql_idx is None: - print(f" {table_name}: 无法定位 user_id"); continue - - batch = [] - success = 0 - fail = 0 - prog = Progress(len(inserts)) - - for values_str in inserts: - vals = split_sql_values(values_str) - if not vals or user_id_sql_idx >= len(vals) or vals[user_id_sql_idx] is None: - fail += 1; prog.update(); continue - - old_user_id = vals[user_id_sql_idx] - yonghuid = user_id_map.get(old_user_id) - if not yonghuid: - fail += 1; prog.update(); continue - - new_uuid = uid_map.get(yonghuid) - if not new_uuid: - fail += 1; prog.update(); continue - - try: - obj = model(user_id=new_uuid) - for sql_idx, field_name in field_map: - if field_name is None or field_name == '_user_id': - continue - if sql_idx < len(vals) and vals[sql_idx] is not None: - try: setattr(obj, field_name, vals[sql_idx]) - except: pass - batch.append(obj) - success += 1 - except Exception: - fail += 1 - - if len(batch) >= BATCH_SIZE: - try: model.objects.bulk_create(batch, ignore_conflicts=True) - except: pass - batch = [] - prog.update() - - if batch: - try: model.objects.bulk_create(batch, ignore_conflicts=True) - except: pass - - prog.finish() - print(f" 成功: {success}, 失败(无user_id): {fail}") - - # [6] 迁移其他引用表 - print("\n[6/7] 迁移其他引用 yonghuid 的表...") - other_tables = [ - 'tixianjilu', 'tixian_shenhe_jilu', 'tixian_auto_record', - 'xiugaijilu', 'ranking_record', - ] - - conn = get_raw_conn(db=DATABASE_NAME) - cursor = conn.cursor() - cursor.execute('SET FOREIGN_KEY_CHECKS = 0') - - for table_name in other_tables: - inserts = parse_insert_values(table_name, sql_content) - if not inserts: - print(f" {table_name}: 0 条"); continue - - success = 0 - prog = Progress(len(inserts)) - - for values_str in inserts: - sql = f"INSERT INTO `{table_name}` VALUES ({values_str})" - try: - cursor.execute(sql) - success += 1 - except Exception: - pass - if success % 100 == 0 and success > 0: - try: conn.commit() - except: pass - prog.update() - - try: conn.commit() - except MySQLdb.OperationalError: - conn = get_raw_conn(db=DATABASE_NAME) - cursor = conn.cursor() - cursor.execute('SET FOREIGN_KEY_CHECKS = 0') - - prog.finish() - print(f" 成功: {success}") - - try: - cursor.execute('SET FOREIGN_KEY_CHECKS = 1') - conn.commit(); conn.close() - except: pass - - # [7] 验证 - print("\n[7/7] 验证迁移结果...") - new_user_count = User.objects.count() - new_ur_count = UserRole.objects.count() - usd_count = UserSensitiveData.objects.count() - - print(f" gvsdsdk.User: {new_user_count}") - print(f" UserRole: {new_ur_count}") - print(f" UserSensitiveData: {usd_count}") - - print("\n 角色分布:") - for user_type, role in created_roles.items(): - ur_count = UserRole.objects.filter(RoleUUID=role.RoleUUID).count() - print(f" {ROLE_MAP[user_type]}: {ur_count} 人") - - print("\n 扩展表:") - for name, model in [('user_dashou', UserDashou), ('user_guanshi', UserGuanshi), - ('user_kefu', UserKefu), ('user_shangjia', UserShangjia), - ('user_boss', UserBoss), ('admin_profile', AdminProfile), - ('user_zuzhang', UserZuzhang), ('user_shenheguan', UserShenheguan)]: - print(f" {name}: {model.objects.count()} 条") - - print("\n" + "=" * 60) - print("迁移完成!") - print(f"TENANT_UUID = {uuid.UUID(bytes=TENANT_UUID)}") - print(f"COMPANY_UUID = {uuid.UUID(bytes=COMPANY_UUID)}") - print("=" * 60) - - -if __name__ == '__main__': - run_migration() diff --git a/show_tables.py b/show_tables.py deleted file mode 100644 index f8d13f6..0000000 --- a/show_tables.py +++ /dev/null @@ -1,13 +0,0 @@ -import MySQLdb - -conn = MySQLdb.connect( - host='gvsds.com', port=50030, user='root', - password='sajksh.sdfGH3YUge.wjkd+', - database='xaio_cheng_xu', charset='utf8mb4' -) -cur = conn.cursor() -cur.execute("SHOW TABLES") -for row in cur.fetchall(): - print(row[0]) -cur.close() -conn.close() diff --git a/users/views.py b/users/views.py index 3f1313e..10588c1 100644 --- a/users/views.py +++ b/users/views.py @@ -1090,7 +1090,7 @@ class ShangJiaXinXiView(APIView): # ------------------- 3. 从 ShangjiaRiTongji 获取今日统计 ------------------- try: - today_stat = ShangjiaRiTongji.query.get(UserUID=yonghuid, riqi=today) + today_stat = ShangjiaRiTongji.query.get(yonghuid=yonghuid, riqi=today) jinri_paifa_dingdan = today_stat.paifa_dingdan_shu jinri_paifa_jine = float(today_stat.paifa_jine) jinri_tuikuan_dingdan = today_stat.tuikuan_dingdan_shu @@ -1105,7 +1105,7 @@ class ShangJiaXinXiView(APIView): # ------------------- 4. 从 ShangjiaRiTongji 获取本月统计 ------------------- month_stats = ShangjiaRiTongji.query.filter( - UserUID=yonghuid, + yonghuid=yonghuid, riqi__gte=this_month_start, riqi__lte=today ).aggregate( @@ -2170,7 +2170,7 @@ class TixianJiluHuoquViewV2(APIView): limit = 100 offset = (page - 1) * limit - qs = Tixianjilu.query.filter(UserUID=yonghuid) + qs = Tixianjilu.query.filter(yonghuid=yonghuid) if mode == 2: # 自动提现:含新审核关联记录;zhuangtai>0 时按状态筛选 if zhuangtai_filter > 0: @@ -5739,7 +5739,7 @@ class YonghuTixianShenheXiugaiView(APIView): try: tixian_record = Tixianjilu.objects.select_for_update().get( id=tixian_id, - UserUID=current_yonghuid # 确保只能修改自己的记录 + yonghuid=current_yonghuid # 确保只能修改自己的记录 ) except Tixianjilu.DoesNotExist: return Response({ @@ -6167,7 +6167,7 @@ class ChufaJiluHuoquView(APIView): zhengju_mapping = {} if dingdan_ids and shangjia_ids: # 构建Q对象:dingdan_id在列表中 AND yonghuid在商家ID列表中 - zhengju_q = Q(dingdan_id__in=dingdan_ids, UserUID__in=shangjia_ids) + zhengju_q = Q(dingdan_id__in=dingdan_ids, yonghuid__in=shangjia_ids) zhengju_queryset = Chufatupian.query.filter(zhengju_q).values('dingdan_id', 'yonghuid', 'tupian') for item in zhengju_queryset: @@ -6362,7 +6362,7 @@ class DashouShensuView(APIView): # 检查是否已经有申诉图片 existing_shensu_tupian = Chufatupian.query.filter( dingdan_id=chufa_record.dingdan_id, - UserUID=yonghuid + yonghuid=yonghuid ).exists() if existing_shensu_tupian: @@ -6609,7 +6609,7 @@ class ShangjiaChufaJiluHuoquView(APIView): shensu_mapping = {} if dingdan_ids and dashou_ids: # 构建Q对象:dingdan_id在列表中 AND yonghuid在打手ID列表中 - shensu_q = Q(dingdan_id__in=dingdan_ids, UserUID__in=dashou_ids) + shensu_q = Q(dingdan_id__in=dingdan_ids, yonghuid__in=dashou_ids) shensu_queryset = Chufatupian.query.filter(shensu_q).values('dingdan_id', 'yonghuid', 'tupian') for item in shensu_queryset: @@ -9198,11 +9198,11 @@ class KefuPunishmentDetailView(APIView): shensu_images = [] try: # 商家证据图片:上传者为请求人 (qingqiuid) - zhengju_qs = Chufatupian.query.filter(dingdan_id=dingdan_id, UserUID=record.qingqiuid) + zhengju_qs = Chufatupian.query.filter(dingdan_id=dingdan_id, yonghuid=record.qingqiuid) zhengju_images = [item.tupian for item in zhengju_qs if item.tupian] # 打手申诉图片:上传者为打手 (dashouid) - shensu_qs = Chufatupian.query.filter(dingdan_id=dingdan_id, UserUID=record.dashouid) + shensu_qs = Chufatupian.query.filter(dingdan_id=dingdan_id, yonghuid=record.dashouid) shensu_images = [item.tupian for item in shensu_qs if item.tupian] except Exception as e: logger.error(f"查询图片失败: {e}") @@ -11940,7 +11940,7 @@ class FaKuanPayPollView(APIView): if not dingdanid: return Response({'code': 400, 'message': '订单ID不能为空'}) - order = Czjilu.query.get(dingdan_id=dingdanid, UserUID=request.user.yonghuid) + order = Czjilu.query.get(dingdan_id=dingdanid, yonghuid=request.user.yonghuid) if order.zhuangtai == 3: return Response({'code': 200, 'message': '支付成功'}) else: @@ -11963,7 +11963,7 @@ class FaKuanPayFailView(APIView): if not dingdanid: return Response({'code': 400, 'message': '订单ID不能为空'}) - order = Czjilu.query.get(dingdan_id=dingdanid, UserUID=request.user.yonghuid) + order = Czjilu.query.get(dingdan_id=dingdanid, yonghuid=request.user.yonghuid) if order.zhuangtai == 9: # 未支付 order.delete() logger.info(f"用户{request.user.yonghuid}删除未支付订单: {dingdanid}") @@ -12375,7 +12375,7 @@ class KaohePayCallbackView(View): # 从临时表获取业务参数并创建审核记录 try: - temp = KaohePayTemp.query.get(dingdan_id=out_trade_no, UserUID=order.yonghuid) + temp = KaohePayTemp.query.get(dingdan_id=out_trade_no, yonghuid=order.yonghuid) logger.info(f"找到临时表记录: {out_trade_no}, 用户ID: {order.yonghuid}") user = User.query.get(UserUID=order.yonghuid) @@ -12495,7 +12495,7 @@ class KaohePayPollView(APIView): if not dingdanid: return Response({'code': 400, 'message': '订单ID不能为空'}) try: - order = Czjilu.query.get(dingdan_id=dingdanid, UserUID=request.user.yonghuid, leixing=5) + order = Czjilu.query.get(dingdan_id=dingdanid, yonghuid=request.user.yonghuid, leixing=5) if order.zhuangtai == 3: return Response({'code': 200, 'message': '支付成功'}) return Response({'code': 400, 'message': '订单尚未支付'}) @@ -12512,7 +12512,7 @@ class KaohePayFailView(APIView): if not dingdanid: return Response({'code': 400, 'message': '订单ID不能为空'}) try: - order = Czjilu.query.get(dingdan_id=dingdanid, UserUID=request.user.yonghuid, leixing=5) + order = Czjilu.query.get(dingdan_id=dingdanid, yonghuid=request.user.yonghuid, leixing=5) if order.zhuangtai == 9: order.delete() return Response({'code': 200, 'message': '订单已删除'}) @@ -12864,7 +12864,7 @@ class TixianQueRenAutoView(APIView): try: auto_record = TixianAutoRecord.objects.select_for_update().get( tixian_id=tixian_id, - UserUID=user_main.yonghuid, + yonghuid=user_main.yonghuid, ) except TixianAutoRecord.DoesNotExist: return Response({'code': 4, 'msg': '提现记录不存在'}, status=status.HTTP_404_NOT_FOUND) diff --git a/verify_fixes.py b/verify_fixes.py deleted file mode 100644 index c1acb1b..0000000 --- a/verify_fixes.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python3 -"""验证所有兼容性修复""" -import os; os.environ['DJANGO_SETTINGS_MODULE']='a_long_dianjing.settings' -import django; django.setup() -from gvsdsdk.models import User -from rest_framework_simplejwt.tokens import RefreshToken -from rest_framework_simplejwt.authentication import JWTAuthentication -from unittest.mock import Mock - -u = User.objects.filter(UserName__isnull=False).first() -print(f'用户: {u.UserName}, UserUID: {u.UserUID}') - -# 1. JWT 认证 -refresh = RefreshToken.for_user(u) -access = refresh.access_token -auth = JWTAuthentication() -request = Mock() -request.META = {'HTTP_AUTHORIZATION': f'Bearer {access}'} -request._request = request -validated_user, _ = auth.authenticate(request) -print(f'1. JWT: {validated_user.UserName}') - -# 2. 兼容属性 -print(f'2. yonghuid: {u.yonghuid}') -print(f' phone: {u.phone}') -print(f' avatar: {u.avatar}') -print(f' ip: {u.ip}') -print(f' last_login_time: {u.last_login_time}') -print(f' shoujihao_renzheng: {u.shoujihao_renzheng}') -print(f' zhifu: {u.zhifu}') -print(f' skzhanghao: {u.skzhanghao}') - -# 3. ORM 查询 -u2 = User.query.get(UserUID=u.UserUID) -print(f'3. User.query.get(UserUID=): {u2.UserName}') - -u3 = User.query.filter(OpenID=u.OpenID).first() -print(f' User.query.filter(OpenID=): {u3.UserName}') - -u4 = User.query.filter(Phone=u.Phone).first() if u.Phone else None -print(f' User.query.filter(Phone=): {u4.UserName if u4 else "N/A"}') - -# 4. user_type -print(f'4. user_type: {u.user_type}') - -# 5. has_role -print(f'5. has_role(dashou): {u.has_role("dashou")}') - -# 6. dashou_profile -dp = u.dashou_profile -print(f'6. dashou_profile: {dp}') - -print('\n所有测试通过!')