序列化
This commit is contained in:
113
Html/apps/_docs/json_serializer_usage.md
Normal file
113
Html/apps/_docs/json_serializer_usage.md
Normal file
@@ -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__`属性
|
||||||
|
- 对于无法序列化的类型,会转换为字符串表示
|
||||||
|
- 确保导入路径正确,特别是在不同模块中使用时
|
||||||
@@ -188,11 +188,17 @@ def upload_learning_progress_to_cloud(progress: Dict) -> Dict:
|
|||||||
base_url = config.get("ASE_ENGINE_URL", "")
|
base_url = config.get("ASE_ENGINE_URL", "")
|
||||||
api_url = f"{base_url}/api/sync/upload"
|
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 = {
|
payload = {
|
||||||
"namespace_url": url_token, # 使用配置中的token作为namespace_url
|
"namespace_url": url_token, # 使用配置中的token作为namespace_url
|
||||||
"user_id": progress.get("user_id", ""),
|
"user_id": progress.get("user_id", ""),
|
||||||
"data": progress
|
"data": serialized_progress
|
||||||
}
|
}
|
||||||
|
|
||||||
# 发送POST请求
|
# 发送POST请求
|
||||||
|
|||||||
58
Html/apps/utils/json_serializer.py
Normal file
58
Html/apps/utils/json_serializer.py
Normal file
@@ -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)
|
||||||
54
Html/test_datetime_serialization.py
Normal file
54
Html/test_datetime_serialization.py
Normal file
@@ -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)
|
||||||
Reference in New Issue
Block a user