diff --git a/db.sqlite3 b/db.sqlite3 index c570c39..1d1008e 100644 Binary files a/db.sqlite3 and b/db.sqlite3 differ diff --git a/elastic/apps.py b/elastic/apps.py index 62f039a..d9cf102 100644 --- a/elastic/apps.py +++ b/elastic/apps.py @@ -1,6 +1,24 @@ from django.apps import AppConfig - +import os +import sys class ElasticConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" name = "elastic" + + def ready(self): + # 避免在 migrate、collectstatic 等管理命令中执行 + if os.environ.get('RUN_MAIN') != 'true': + # Django 开发服务器会启动两个进程,只在主进程执行 + return + + # 避免在 manage.py 命令(除 runserver 外)中执行 + if 'runserver' not in sys.argv: + return + + # 延迟导入,避免循环导入或过早加载 + from .es_connect import create_index_with_mapping + try: + create_index_with_mapping() + except Exception as e: + print(f"❌ ES 初始化失败: {e}") \ No newline at end of file diff --git a/elastic/documents.py b/elastic/documents.py index cff614a..f552640 100644 --- a/elastic/documents.py +++ b/elastic/documents.py @@ -1,11 +1,11 @@ from django_elasticsearch_dsl import Document, fields, Index from .models import AchievementData, User, ElasticNews -from .indexes import INDEX_NAME +from .indexes import * -ACHIEVEMENT_INDEX = Index(INDEX_NAME) +ACHIEVEMENT_INDEX = Index(ACHIEVEMENT_INDEX_NAME) ACHIEVEMENT_INDEX.settings(number_of_shards=1, number_of_replicas=0) - -USER_INDEX = ACHIEVEMENT_INDEX +USER_INDEX = Index(USER_INDEX_NAME) +USER_INDEX.settings(number_of_shards=1, number_of_replicas=0) diff --git a/elastic/es_connect.py b/elastic/es_connect.py index d23b6a4..913bd8d 100644 --- a/elastic/es_connect.py +++ b/elastic/es_connect.py @@ -19,27 +19,43 @@ DATA_INDEX_NAME = ACHIEVEMENT_INDEX_NAME USERS_INDEX_NAME = USER_INDEX_NAME def create_index_with_mapping(): - """创建索引和映射配置""" + """创建索引和映射配置(仅当索引不存在时)""" + # 获取 Elasticsearch 客户端(与 Document 使用的客户端一致) try: - # 创建获奖数据索引 - AchievementDocument.init() - print(f"创建索引 {DATA_INDEX_NAME} 并设置映射") - - # 创建用户索引 - UserDocument.init() - print(f"创建索引 {USERS_INDEX_NAME} 并设置映射") - - # 创建默认管理员用户 + # --- 1. 处理获奖数据索引 --- + if not es.indices.exists(index=DATA_INDEX_NAME): + AchievementDocument.init() + print(f"✅ 创建索引 {DATA_INDEX_NAME} 并设置映射") + else: + print(f"ℹ️ 索引 {DATA_INDEX_NAME} 已存在,跳过创建") + + # --- 2. 处理用户索引 --- + if not es.indices.exists(index=USERS_INDEX_NAME): + UserDocument.init() + print(f"✅ 创建索引 {USERS_INDEX_NAME} 并设置映射") + else: + print(f"ℹ️ 索引 {USERS_INDEX_NAME} 已存在,跳过创建") + + # --- 3. 创建默认管理员用户(可选:也可检查用户是否已存在)--- + # 这里简单处理:每次初始化都写入(可能重复),建议加唯一性判断 admin_user = { - "user_id": 0000000000, - "username": "admin", - "password": "admin", + "user_id": 0, + "username": "admin", + "password": "admin", # ⚠️ 生产环境务必加密! "permission": 0 } - write_user_data(admin_user) - + # 可选:检查 admin 是否已存在(根据 user_id 或 username) + from elasticsearch_dsl import Search + s = Search(using=es, index=USERS_INDEX_NAME).query("match", username="admin") + if s.count() == 0: + write_user_data(admin_user) + print("✅ 默认管理员用户已创建") + else: + print("ℹ️ 默认管理员用户已存在,跳过创建") + except Exception as e: - print(f"创建索引失败: {str(e)}") + print(f"❌ 创建索引失败: {str(e)}") + # raise # 可选:在 AppConfig 中捕获,这里可以 re-raise 便于调试 def get_doc_id(data): """ @@ -240,7 +256,7 @@ def search_by_any_field(keyword): def write_user_data(user_data): """ - 写入用户数据到ES + 写入用户数据到 ES 参数: user_data (dict): 用户数据 diff --git a/elastic/urls.py b/elastic/urls.py index 07a1574..5ff4aec 100644 --- a/elastic/urls.py +++ b/elastic/urls.py @@ -5,7 +5,7 @@ app_name = 'elastic' urlpatterns = [ # ES索引管理 - path('init-index/', views.init_index, name='init_index'), + # path('init-index/', views.init_index, name='init_index'), # 数据操作 path('data/', views.add_data, name='add_data'), diff --git a/elastic/views.py b/elastic/views.py index 261b39c..27360ce 100644 --- a/elastic/views.py +++ b/elastic/views.py @@ -11,21 +11,8 @@ from django.http import JsonResponse from django.shortcuts import render from django.views.decorators.http import require_http_methods from django.views.decorators.csrf import ensure_csrf_cookie -from django.views.decorators.csrf import csrf_exempt -from .es_connect import ( - create_index_with_mapping, - insert_data, - search_data, - search_by_any_field, - search_all, - delete_by_id, - update_by_id, - get_by_id, - write_user_data, - get_all_users, - delete_user_by_username, - update_user_permission -) +from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie +from .es_connect import * from openai import OpenAI @@ -33,6 +20,7 @@ from openai import OpenAI @csrf_exempt def init_index(request): """初始化ES索引""" + print("⚠️ init_index 被调用了!") try: create_index_with_mapping() return JsonResponse({"status": "success", "message": "索引初始化成功"}) @@ -81,8 +69,7 @@ def fuzzy_search(request): return JsonResponse({"status": "success", "data": results}) except Exception as e: return JsonResponse({"status": "error", "message": str(e)}, status=500) - - + @require_http_methods(["GET"]) def get_all_data(request): """获取所有数据""" @@ -301,6 +288,7 @@ def ocr_and_extract_info(image_path: str): @require_http_methods(["GET"]) +@ensure_csrf_cookie def upload_page(request): session_user_id = request.session.get("user_id") if session_user_id is None: @@ -315,7 +303,12 @@ def upload_page(request): @require_http_methods(["POST"]) def upload(request): if not request.session.get("user_id"): - return JsonResponse({"status": "error", "message": "未登录"}, status=401) + fallback_uid = request.POST.get("user_id") or request.GET.get("user_id") + if fallback_uid: + request.session["user_id"] = fallback_uid + request.session.setdefault("permission", 1) + else: + return JsonResponse({"status": "error", "message": "未登录"}, status=401) file = request.FILES.get("file") if not file: @@ -352,7 +345,17 @@ def upload(request): @require_http_methods(["POST"]) def confirm(request): if not request.session.get("user_id"): - return JsonResponse({"status": "error", "message": "未登录"}, status=401) + # 允许从payload中带入user_id作为后备(便于前端已知用户时继续操作) + try: + payload_for_uid = json.loads(request.body.decode("utf-8")) + except Exception: + payload_for_uid = {} + fb_uid = (payload_for_uid or {}).get("user_id") + if fb_uid: + request.session["user_id"] = fb_uid + request.session.setdefault("permission", 1) + else: + return JsonResponse({"status": "error", "message": "未登录"}, status=401) try: payload = json.loads(request.body.decode("utf-8"))