#!/usr/bin/env python """ 初始化数据库脚本 1. 导入标准MBTI 93题题库 2. 创建Django后台管理员账号 """ import os import sys import csv # 添加项目根目录到Python路径 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, BASE_DIR) import django os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mbti_site.settings') django.setup() from django.contrib.auth import get_user_model from mbti.models import Question, Questionnaire, TypeProfile User = get_user_model() def load_standard_questions(csv_path): """加载标准MBTI 93题,合并成对的单词选择""" items = [] paired_questions = {} # 用于存储成对的题目 {question_number: {dimension, options, order}} processed_questions = set() # 记录已处理的题目编号,避免重复 with open(csv_path, 'r', encoding='utf-8-sig') as f: reader = csv.DictReader(f) for row_num, row in enumerate(reader, start=2): # 从第2行开始(第1行是标题) try: text = (row.get('text') or '').strip().strip('"') # 去除引号 dimension = (row.get('dimension') or '').strip().upper() keyed_pole = (row.get('keyed_pole') or '').strip().upper() # 安全地解析 question_number qn_str = (row.get('question_number') or '').strip() try: question_number = int(qn_str) if qn_str else 0 except ValueError: print(f"[WARN] 第 {row_num} 行 question_number 格式错误: {qn_str},跳过") continue scoring_rule = (row.get('scoring_rule') or '').strip() # 安全地解析 weight weight_str = (row.get('weight') or '1').strip() try: weight = int(weight_str) if weight_str else 1 except ValueError: weight = 1 # 安全地解析 order order_str = (row.get('order') or str(question_number)).strip() try: order = int(order_str) if order_str else question_number except ValueError: order = question_number if not text or dimension not in ['IE', 'SN', 'TF', 'JP']: print(f"[WARN] 第 {row_num} 行数据不完整,跳过") continue # 判断是否是成对的单词选择(第二部分:27-73题,且文本中没有A)或B)) is_paired_choice = (27 <= question_number <= 73) and "A)" not in text and "B)" not in text if is_paired_choice: # 成对的单词选择,需要合并 if question_number not in paired_questions: paired_questions[question_number] = { 'dimension': dimension, 'options': [], 'order': order, } # 确定这是A选项还是B选项 is_option_a = scoring_rule.endswith('_A') paired_questions[question_number]['options'].append({ 'text': text, 'keyed_pole': keyed_pole, 'is_a': is_option_a, 'scoring_rule': scoring_rule, }) else: # 第一部分和第三部分,直接添加(但要去除已处理的成对题目) if question_number not in processed_questions: items.append({ 'text': text, 'dimension': dimension, 'keyed_pole': keyed_pole, 'question_number': question_number, 'scoring_rule': scoring_rule, 'weight': weight, 'order': order, }) processed_questions.add(question_number) except Exception as e: print(f"[ERROR] 第 {row_num} 行处理失败: {e},跳过") continue # 处理成对的题目,合并成一个题目 for q_num, pair_data in sorted(paired_questions.items()): options = pair_data['options'] if len(options) == 2: # 按A/B顺序排序(A在前) options.sort(key=lambda x: not x['is_a']) # 构建合并后的题目文本 combined_text = f"你更容易喜欢或倾向哪一个词? A) {options[0]['text']} B) {options[1]['text']}" items.append({ 'text': combined_text, 'dimension': pair_data['dimension'], 'keyed_pole': options[0]['keyed_pole'], # 使用第一个选项的keyed_pole 'question_number': q_num, 'scoring_rule': options[0]['scoring_rule'], 'weight': 1, 'order': pair_data['order'], }) processed_questions.add(q_num) else: print(f"[WARN] 题目 {q_num} 的选项数量不是2(实际{len(options)}),跳过合并") # 按order排序 items.sort(key=lambda x: x['order']) print(f"[INFO] 合并后共 {len(items)} 题(标准MBTI应为93题)") return items def import_questions(): """导入标准MBTI题库(从JSON文件)""" print("=" * 50) print("开始导入标准MBTI题库...") print("=" * 50) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 项目根目录 json_path = os.path.join(BASE_DIR, 'data', 'questions_standard_mbti_93.json') if not os.path.exists(json_path): print(f"❌ 题库文件不存在:{json_path}") return False # 使用JSON导入脚本 try: from database_management.add_questions_from_json import import_questions_from_json import_questions_from_json(json_path) return True except Exception as e: print(f"❌ 导入失败:{e}") import traceback traceback.print_exc() return False def create_admin_user(): """创建Django后台管理员账号""" print("\n" + "=" * 50) print("创建Django后台管理员账号...") print("=" * 50) USERNAME = 'admin' EMAIL = 'admin@example.com' PASSWORD = 'admin@123..' # 检查用户是否已存在 if User.objects.filter(username=USERNAME).exists(): print(f"用户 {USERNAME} 已存在,更新密码...") user = User.objects.get(username=USERNAME) user.set_password(PASSWORD) user.is_staff = True user.is_superuser = True user.save() print(f"✓ 已更新用户 {USERNAME} 的密码") else: # 创建新用户 user = User.objects.create_superuser( username=USERNAME, email=EMAIL, password=PASSWORD ) print(f"✓ 已创建管理员账号:{USERNAME}") print(f"\n管理员账号信息:") print(f" 用户名: {USERNAME}") print(f" 密码: {PASSWORD}") print(f" 访问地址: http://localhost:8989/admin/") def main(): """主函数""" print("\n" + "=" * 50) print("数据库初始化脚本") print("=" * 50) # 1. 导入题库 if not import_questions(): print("❌ 题库导入失败,终止初始化") sys.exit(1) # 2. 创建管理员账号 create_admin_user() print("\n" + "=" * 50) print("✅ 数据库初始化完成!") print("=" * 50) print("\n下一步:") print("1. 访问 http://localhost:8989/admin/ 登录管理后台") print("2. 使用账号 admin / admin@123.. 登录") print("3. 可以导入16种人格类型数据:python populate_personality_data.py") if __name__ == '__main__': try: main() except KeyboardInterrupt: print("\n\n❌ 操作被用户中断") sys.exit(1) except Exception as e: print(f"\n\n❌ 发生错误: {e}") import traceback traceback.print_exc() sys.exit(1)