v0.2 Preview: Construction Plan.
CI / test (push) Failing after 1m31s

This commit is contained in:
2026-08-08 21:25:27 +08:00
parent b88d15698a
commit 1f98f7152d
822 changed files with 96959 additions and 8 deletions
View File
+3
View File
@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.
+18
View File
@@ -0,0 +1,18 @@
from rest_framework.views import exception_handler as drf_exception_handler
def exception_handler(exc, context):
response = drf_exception_handler(exc, context)
if response is None:
return response
request = context.get("request")
response.data = {
"error": {
"code": getattr(exc, "default_code", "request_error"),
"message": "请求未能完成",
"details": response.data,
"request_id": getattr(request, "request_id", None),
}
}
return response
+6
View File
@@ -0,0 +1,6 @@
from django.apps import AppConfig
class CommonConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'common'
+17
View File
@@ -0,0 +1,17 @@
from channels.generic.websocket import AsyncJsonWebsocketConsumer
class HealthConsumer(AsyncJsonWebsocketConsumer):
group_name = "healthcheck"
async def connect(self):
try:
await self.channel_layer.group_add(self.group_name, self.channel_name)
await self.channel_layer.group_discard(self.group_name, self.channel_name)
except Exception:
await self.close(code=1011)
return
await self.accept()
await self.send_json({"status": "ok", "channel_layer": "ok"})
await self.close()
+11
View File
@@ -0,0 +1,11 @@
import contextvars
import logging
request_id_context = contextvars.ContextVar("request_id", default="-")
class RequestIDFilter(logging.Filter):
def filter(self, record):
record.request_id = request_id_context.get()
return True
+1
View File
@@ -0,0 +1 @@
@@ -0,0 +1 @@
@@ -0,0 +1,63 @@
import re
from django.core.management.base import BaseCommand, CommandError
from django.db import connection
MINIMUM_VERSION = (8, 0, 35)
class Command(BaseCommand):
help = "检查生产 MySQL 的版本、字符集、引擎、严格模式和事务隔离级别"
def handle(self, *args, **options):
if connection.vendor != "mysql":
raise CommandError(f"数据库必须是 MySQL,当前为 {connection.vendor}")
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT VERSION(),
@@character_set_server,
@@collation_server,
@@sql_mode,
@@transaction_isolation,
@@default_storage_engine
"""
)
(
version_text,
charset,
collation,
sql_mode,
isolation,
storage_engine,
) = cursor.fetchone()
match = re.match(r"^(\d+)\.(\d+)\.(\d+)", version_text)
if match is None:
raise CommandError(f"无法解析 MySQL 版本: {version_text}")
version = tuple(int(part) for part in match.groups())
if version < MINIMUM_VERSION:
minimum = ".".join(str(part) for part in MINIMUM_VERSION)
raise CommandError(f"MySQL 版本过低: {version_text},最低要求 {minimum}")
if charset.lower() != "utf8mb4":
raise CommandError(f"character_set_server 必须是 utf8mb4,当前为 {charset}")
if not collation.lower().startswith("utf8mb4_"):
raise CommandError(f"collation_server 必须属于 utf8mb4,当前为 {collation}")
modes = {mode.strip().upper() for mode in sql_mode.split(",")}
if not {"STRICT_TRANS_TABLES", "STRICT_ALL_TABLES"} & modes:
raise CommandError(f"MySQL 未启用严格模式: {sql_mode}")
if isolation.upper().replace("_", "-") != "READ-COMMITTED":
raise CommandError(f"事务隔离级别必须是 READ-COMMITTED,当前为 {isolation}")
if storage_engine.lower() != "innodb":
raise CommandError(f"默认存储引擎必须是 InnoDB,当前为 {storage_engine}")
self.stdout.write(
self.style.SUCCESS(
"MySQL 检查通过: "
f"version={version_text}, charset={charset}, "
f"collation={collation}, isolation={isolation}, engine={storage_engine}"
)
)
+19
View File
@@ -0,0 +1,19 @@
import uuid
from .logging import request_id_context
class RequestIDMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
request_id = request.headers.get("X-Request-ID") or str(uuid.uuid4())
request.request_id = request_id
token = request_id_context.set(request_id)
try:
response = self.get_response(request)
response["X-Request-ID"] = request_id
return response
finally:
request_id_context.reset(token)
+3
View File
@@ -0,0 +1,3 @@
from django.db import models
# Create your models here.
+3
View File
@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.
+14
View File
@@ -0,0 +1,14 @@
from django.db import connection
from django.http import JsonResponse
from django.shortcuts import render
def home(request):
return render(request, "index.html")
def health(request):
with connection.cursor() as cursor:
cursor.execute("SELECT 1")
cursor.fetchone()
return JsonResponse({"status": "ok", "database": "ok"})