diff --git a/Html/apps/_docs/json_serializer_usage.md b/Html/apps/_docs/json_serializer_usage.md new file mode 100644 index 0000000..528b724 --- /dev/null +++ b/Html/apps/_docs/json_serializer_usage.md @@ -0,0 +1,113 @@ +# JSON Serializer 用法文档 + +## 概述 + +`json_serializer` 是一个通用的JSON序列化工具,用于处理Python中常见的非JSON序列化类型,如`datetime`、`date`、`time`、`ObjectId`等。 + +## 支持的类型 + +- `datetime`: 转换为ISO格式字符串 +- `date`: 转换为ISO格式字符串 +- `time`: 转换为ISO格式字符串 +- `ObjectId`: 转换为字符串 +- `bytes`: 转换为UTF-8字符串 +- `set`/`frozenset`: 转换为列表 +- 其他不可序列化类型: 转换为字符串表示 + +## 安装位置 + +位于 `apps/utils/json_serializer.py` + +## 使用方法 + +### 导入 + +```python +from apps.utils.json_serializer import json_serialize, json_serialize_dict, JSONEncoder +``` + +### 函数说明 + +1. **json_serialize(obj)**: 将对象序列化为JSON字符串 + - 参数: `obj` - 要序列化的对象 + - 返回: JSON字符串 + +2. **json_serialize_dict(obj)**: 将对象转换为可JSON序列化的字典 + - 参数: `obj` - 要序列化的对象 + - 返回: 可JSON序列化的字典 + +3. **JSONEncoder**: 自定义JSON编码器类,可直接用于`json.dumps()` + +### 示例 + +#### 基本使用 + +```python +from datetime import datetime +from apps.utils.json_serializer import json_serialize_dict + +# 创建包含datetime的字典 +data = { + "user_id": "test_user", + "updated_at": datetime.now(), + "scores": [85, 90, 95] +} + +# 序列化 +serialized = json_serialize_dict(data) +print(serialized) +# 输出: {"user_id": "test_user", "updated_at": "2025-12-10T15:30:45.123456", "scores": [85, 90, 95]} +``` + +#### 在API请求中使用 + +```python +import requests +from apps.utils.json_serializer import json_serialize_dict + +# 准备请求数据 +data = { + "user_id": "test_user", + "updated_at": datetime.now(), + "progress": {"chapter1": "completed", "chapter2": "in_progress"} +} + +# 序列化数据 +serialized_data = json_serialize_dict(data) + +# 发送请求 +response = requests.post( + "https://api.example.com/upload", + json=serialized_data, + headers={"Content-Type": "application/json"} +) +``` + +#### 直接使用JSONEncoder + +```python +import json +from datetime import datetime +from apps.utils.json_serializer import JSONEncoder + +# 创建数据 +data = {"updated_at": datetime.now()} + +# 使用自定义编码器 +json_str = json.dumps(data, cls=JSONEncoder, ensure_ascii=False) +print(json_str) +# 输出: {"updated_at": "2025-12-10T15:30:45.123456"} +``` + +## 应用场景 + +1. API请求中的数据序列化 +2. 保存数据到文件或数据库 +3. 跨服务数据传输 +4. 日志记录中的复杂对象序列化 + +## 注意事项 + +- 对于自定义对象,会尝试序列化其`__dict__`属性 +- 对于无法序列化的类型,会转换为字符串表示 +- 确保导入路径正确,特别是在不同模块中使用时 diff --git a/Html/apps/services/course_services/learning_progess_process.py b/Html/apps/services/course_services/learning_progess_process.py index ff0cc1c..430c0d2 100644 --- a/Html/apps/services/course_services/learning_progess_process.py +++ b/Html/apps/services/course_services/learning_progess_process.py @@ -188,11 +188,17 @@ def upload_learning_progress_to_cloud(progress: Dict) -> Dict: base_url = config.get("ASE_ENGINE_URL", "") api_url = f"{base_url}/api/sync/upload" + # 导入JSON序列化工具 + from ...utils.json_serializer import json_serialize_dict + + # 序列化进度数据,处理datetime等特殊类型 + serialized_progress = json_serialize_dict(progress) + # 构建请求参数 payload = { "namespace_url": url_token, # 使用配置中的token作为namespace_url "user_id": progress.get("user_id", ""), - "data": progress + "data": serialized_progress } # 发送POST请求 diff --git a/Html/apps/utils/json_serializer.py b/Html/apps/utils/json_serializer.py new file mode 100644 index 0000000..ea60443 --- /dev/null +++ b/Html/apps/utils/json_serializer.py @@ -0,0 +1,58 @@ +import json +from datetime import datetime, date, time +from bson import ObjectId +from typing import Any, Dict, List, Union + + +class JSONEncoder(json.JSONEncoder): + """ + 通用JSON编码器,处理常见的非JSON序列化类型 + + 支持的特殊类型: + - datetime: 转换为ISO格式字符串 + - date: 转换为ISO格式字符串 + - time: 转换为ISO格式字符串 + - ObjectId: 转换为字符串 + - 其他不可序列化类型: 转换为字符串表示 + """ + + def default(self, obj: Any) -> Any: + if isinstance(obj, (datetime, date, time)): + return obj.isoformat() + elif isinstance(obj, ObjectId): + return str(obj) + elif isinstance(obj, bytes): + return obj.decode('utf-8', errors='replace') + elif isinstance(obj, (set, frozenset)): + return list(obj) + elif hasattr(obj, '__dict__'): + return obj.__dict__ + else: + return str(obj) + + +def json_serialize(obj: Any) -> str: + """ + 通用JSON序列化函数,处理常见的非JSON序列化类型 + + 参数: + - obj: 要序列化的对象 + + 返回: + - str: JSON字符串 + """ + return json.dumps(obj, cls=JSONEncoder, ensure_ascii=False) + + +def json_serialize_dict(obj: Any) -> Dict: + """ + 通用JSON序列化函数,将对象转换为可JSON序列化的字典 + + 参数: + - obj: 要序列化的对象 + + 返回: + - Dict: 可JSON序列化的字典 + """ + json_str = json_serialize(obj) + return json.loads(json_str) diff --git a/Html/test_datetime_serialization.py b/Html/test_datetime_serialization.py new file mode 100644 index 0000000..52c5956 --- /dev/null +++ b/Html/test_datetime_serialization.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 + +import sys +import os +from datetime import datetime + +# Add the project root to the Python path +sys.path.insert(0, '/Users/cakecai/Documents/gitea/hsa/Html') + +# Test the JSON serializer +try: + from apps.utils.json_serializer import json_serialize, json_serialize_dict, JSONEncoder + import json + + # Create a test dictionary with datetime object + test_data = { + "user_id": "test_user", + "material_id": "test_course", + "chapter_name": "test_chapter", + "lesson_name": "test_lesson", + "chat_historys": [], + "scores": [], + "chapter_chain_now": None, + "updated_at": datetime.now() + } + + print("Testing datetime serialization...") + print(f"Original data: {test_data}") + print(f"Type of updated_at: {type(test_data['updated_at'])}") + + # Test json_serialize function + json_str = json_serialize(test_data) + print(f"\nSerialized JSON string: {json_str}") + + # Test json_serialize_dict function + serialized_dict = json_serialize_dict(test_data) + print(f"\nSerialized dictionary: {serialized_dict}") + print(f"Type of updated_at in serialized dict: {type(serialized_dict['updated_at'])}") + + # Test direct json.dumps with custom encoder + json_str2 = json.dumps(test_data, cls=JSONEncoder, ensure_ascii=False) + print(f"\nDirect json.dumps with custom encoder: {json_str2}") + + # Verify it can be parsed back + parsed = json.loads(json_str) + print(f"\nParsed back from JSON: {parsed}") + + print("\n✅ All tests passed! datetime objects can be correctly serialized to JSON.") + +except Exception as e: + print(f"\n❌ Test failed with error: {e}") + import traceback + traceback.print_exc() + sys.exit(1)