From 83a9dd04ba9640d18c14a284490b773a5f542779 Mon Sep 17 00:00:00 2001 From: Viajero-tect <2737079298@qq.com> Date: Thu, 13 Nov 2025 21:58:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E2=80=9C=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db.sqlite3 | Bin 131072 -> 131072 bytes elastic/apps.py | 20 ++++++++++++++++- elastic/documents.py | 8 +++---- elastic/es_connect.py | 50 ++++++++++++++++++++++++++++-------------- elastic/urls.py | 2 +- elastic/views.py | 41 ++++++++++++++++++---------------- 6 files changed, 79 insertions(+), 42 deletions(-) diff --git a/db.sqlite3 b/db.sqlite3 index c570c39a3ba8db49d407b1e67d7042b5f2188a97..1d1008efc1f014fcfd64e7c367c9a4d5634df67b 100644 GIT binary patch delta 583 zcmajcJ#W)c6o6qn1yq5+Vg^M;Dr2f^JJ)t1gqj*b?8LH(UE5?K_qzTfwj1K$8)s?K zft8Q!u(489shv9UADH?>7zwJ_0?bD`dY^OV^Ue8u^Zh;g;=_HJzW6ry^6o~PV%m4C z(+68WZ!fQXGL9Bz<+^qZTM-JNmlA=WguDPVBqRsqQ1IC_LPHS+!H%z%V|zH(O>L%{ z9^19*yirPxu9Z0Dex~rU*adk`lv2n^x9}CIjdC*<4Vgz^V!P&ZTlJjL6eX(vLS{Qb zs&;USjt=%^@}$p4S*^(ysv8Rn{}zliaSu`>wu#u>c?+ZDP?#R#G_aQ)5)yBUKIL6w16x0qFkY? z|5h(2pC1iyX6LvK{`4U(FnP6P-}n(QdwO8$+Meqaq=n^IMJZ={jtyseASaFbx;_DL z91w3ZmlVyMQ_MMYd3ty7mRWxM`cT>4(CGg?qOziGuV*Emgv%lh1$caNc0%9UrN6Is WpD~ZC)r}UtF6Qc3f16&VR(=5n;|u#W1@^RJ2bzf($}Qa$2UHps@%CS*tf!~Dmlle${;5o%Oc*VDm&ZNJH0%>xxC8P z&!RX#%Q3w&xFk5hJI%#AIXm6k(9y`SBqz!-EV3da*}2>~J~=qs+sd%aE6lXSDlxDk z&A>3x(#hA~EWj~7-Q3qQD9OOMKsP-v%E-exCBVZpKRrF&C&wh+z{tSJRM*f@*T`JK z(9p`j$jZo6&(hG+%-EcPf#I8PQ>mj-Ql+V3R&u6ks-cNNicw*aNt$J0R(hpDl7UHL zu0iT#n|TtPRj!SO9IU>Lg_EV{DNZh!ZxiF|VE}VaajH*>YgS5NRa9g|YOqUYp__|u zUa(_iv0;^$tFND7v6*{HMQT_`K(Z%R=a?E9n;3He-NVR#n}Po}|Lx6!32pq7C#_f2 yVD@Ds7J~iHfm0gn9u5Eq_?B(} 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"))