feat: 中文化 django-admin 字段标签 (T-603)
This commit is contained in:
+11
-11
@@ -8,10 +8,10 @@ from .security import AiKeyEncryptionError, encrypt_api_key
|
||||
|
||||
class AiModelAdminForm(forms.ModelForm):
|
||||
api_key = forms.CharField(
|
||||
label="API key",
|
||||
label="API Key",
|
||||
required=False,
|
||||
widget=forms.PasswordInput(render_value=False),
|
||||
help_text="Leave blank to keep the existing encrypted key.",
|
||||
help_text="留空表示保留已有加密密钥。",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
@@ -33,7 +33,7 @@ class AiModelAdminForm(forms.ModelForm):
|
||||
cleaned_data = super().clean()
|
||||
api_key = cleaned_data.get("api_key")
|
||||
if not self.instance.pk and not api_key:
|
||||
raise forms.ValidationError("API key is required when creating an AI model.")
|
||||
raise forms.ValidationError("创建 AI 模型时必须填写 API Key。")
|
||||
if api_key:
|
||||
try:
|
||||
self._api_key_encrypted = encrypt_api_key(api_key)
|
||||
@@ -71,14 +71,14 @@ class AiModelAdmin(admin.ModelAdmin):
|
||||
fieldsets = (
|
||||
(None, {"fields": ("name", "url", "model", "api_type", "is_active")}),
|
||||
(
|
||||
"Credentials",
|
||||
"凭证",
|
||||
{
|
||||
"fields": ("api_key", "api_key_status"),
|
||||
"description": "The stored key is encrypted and never displayed.",
|
||||
"description": "已保存的密钥会加密存储,后台不会回显明文。",
|
||||
},
|
||||
),
|
||||
(
|
||||
"Capabilities and request defaults",
|
||||
"能力与请求默认值",
|
||||
{
|
||||
"fields": (
|
||||
"capabilities",
|
||||
@@ -88,16 +88,16 @@ class AiModelAdmin(admin.ModelAdmin):
|
||||
)
|
||||
},
|
||||
),
|
||||
("Timestamps", {"fields": ("created_at", "updated_at")}),
|
||||
("时间信息", {"fields": ("created_at", "updated_at")}),
|
||||
)
|
||||
|
||||
@admin.display(description="capabilities")
|
||||
@admin.display(description="能力")
|
||||
def capabilities_display(self, obj):
|
||||
return ", ".join(sorted(obj.capabilities_set()))
|
||||
|
||||
@admin.display(description="API key")
|
||||
@admin.display(description="API Key")
|
||||
def api_key_status(self, obj):
|
||||
return obj.api_key_masked or "not set"
|
||||
return obj.api_key_masked or "未设置"
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
before = _snapshot_existing(obj) if change else None
|
||||
@@ -241,7 +241,7 @@ class AiConfigAuditLogAdmin(admin.ModelAdmin):
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
@admin.display(description="changed fields")
|
||||
@admin.display(description="变更字段")
|
||||
def changed_fields_display(self, obj):
|
||||
return ", ".join(obj.changed_fields)
|
||||
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
# Generated by Django 5.2.15 on 2026-07-04 08:02
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ai', '0003_alter_aiconfigauditlog_options_alter_aimodel_options_and_more'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='aiconfigauditlog',
|
||||
name='action',
|
||||
field=models.CharField(choices=[('create', '创建'), ('update', '更新'), ('delete', '删除')], max_length=16, verbose_name='动作'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aiconfigauditlog',
|
||||
name='actor',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='操作人'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aiconfigauditlog',
|
||||
name='changed_fields',
|
||||
field=models.JSONField(blank=True, default=list, verbose_name='变更字段'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aiconfigauditlog',
|
||||
name='changes',
|
||||
field=models.JSONField(blank=True, default=dict, verbose_name='变更内容'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aiconfigauditlog',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now_add=True, verbose_name='创建时间'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aiconfigauditlog',
|
||||
name='target_id',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True, verbose_name='目标 ID'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aiconfigauditlog',
|
||||
name='target_repr',
|
||||
field=models.CharField(max_length=255, verbose_name='目标描述'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aiconfigauditlog',
|
||||
name='target_type',
|
||||
field=models.CharField(choices=[('ai_model', 'AI 模型'), ('model_alias', '能力别名')], max_length=32, verbose_name='目标类型'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aimodel',
|
||||
name='api_key_encrypted',
|
||||
field=models.TextField(blank=True, editable=False, verbose_name='加密 API Key'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aimodel',
|
||||
name='api_type',
|
||||
field=models.CharField(choices=[('auto', '自动'), ('chat', '聊天补全'), ('gemini', 'Gemini'), ('images', '图片生成'), ('images_edits', '图片编辑')], default='auto', max_length=32, verbose_name='API 类型'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aimodel',
|
||||
name='capabilities',
|
||||
field=models.JSONField(blank=True, default=list, verbose_name='能力'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aimodel',
|
||||
name='connect_timeout_seconds',
|
||||
field=models.PositiveIntegerField(default=30, verbose_name='连接超时秒数'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aimodel',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now_add=True, verbose_name='创建时间'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aimodel',
|
||||
name='extra_body',
|
||||
field=models.JSONField(blank=True, default=dict, verbose_name='额外请求体'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aimodel',
|
||||
name='is_active',
|
||||
field=models.BooleanField(default=True, verbose_name='启用'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aimodel',
|
||||
name='model',
|
||||
field=models.CharField(max_length=128, verbose_name='模型标识'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aimodel',
|
||||
name='name',
|
||||
field=models.CharField(max_length=128, unique=True, verbose_name='名称'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aimodel',
|
||||
name='timeout_seconds',
|
||||
field=models.PositiveIntegerField(default=0, help_text='0 表示使用 provider 默认值。', verbose_name='请求超时秒数'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aimodel',
|
||||
name='updated_at',
|
||||
field=models.DateTimeField(auto_now=True, verbose_name='更新时间'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='aimodel',
|
||||
name='url',
|
||||
field=models.URLField(max_length=500, verbose_name='接口 URL'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='modelalias',
|
||||
name='ai_model',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='aliases', to='ai.aimodel', verbose_name='AI 模型'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='modelalias',
|
||||
name='alias',
|
||||
field=models.SlugField(max_length=64, verbose_name='能力别名'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='modelalias',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now_add=True, verbose_name='创建时间'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='modelalias',
|
||||
name='is_active',
|
||||
field=models.BooleanField(default=True, verbose_name='启用'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='modelalias',
|
||||
name='is_default',
|
||||
field=models.BooleanField(default=False, verbose_name='默认别名'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='modelalias',
|
||||
name='operation_type',
|
||||
field=models.CharField(choices=[('title', '生成标题'), ('image', '生成图片')], max_length=32, verbose_name='操作类型'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='modelalias',
|
||||
name='updated_at',
|
||||
field=models.DateTimeField(auto_now=True, verbose_name='更新时间'),
|
||||
),
|
||||
]
|
||||
+39
-35
@@ -11,31 +11,33 @@ from .security import decrypt_api_key, encrypt_api_key, mask_secret
|
||||
|
||||
class AiModel(models.Model):
|
||||
class ApiType(models.TextChoices):
|
||||
AUTO = "auto", "Auto"
|
||||
CHAT = "chat", "Chat completions"
|
||||
AUTO = "auto", "自动"
|
||||
CHAT = "chat", "聊天补全"
|
||||
GEMINI = "gemini", "Gemini"
|
||||
IMAGES = "images", "Images generations"
|
||||
IMAGES_EDITS = "images_edits", "Images edits"
|
||||
IMAGES = "images", "图片生成"
|
||||
IMAGES_EDITS = "images_edits", "图片编辑"
|
||||
|
||||
name = models.CharField(max_length=128, unique=True)
|
||||
url = models.URLField(max_length=500)
|
||||
model = models.CharField(max_length=128)
|
||||
name = models.CharField("名称", max_length=128, unique=True)
|
||||
url = models.URLField("接口 URL", max_length=500)
|
||||
model = models.CharField("模型标识", max_length=128)
|
||||
api_type = models.CharField(
|
||||
"API 类型",
|
||||
max_length=32,
|
||||
choices=ApiType.choices,
|
||||
default=ApiType.AUTO,
|
||||
)
|
||||
api_key_encrypted = models.TextField(blank=True, editable=False)
|
||||
capabilities = models.JSONField(default=list, blank=True)
|
||||
api_key_encrypted = models.TextField("加密 API Key", blank=True, editable=False)
|
||||
capabilities = models.JSONField("能力", default=list, blank=True)
|
||||
timeout_seconds = models.PositiveIntegerField(
|
||||
"请求超时秒数",
|
||||
default=0,
|
||||
help_text="0 means use provider resolution defaults.",
|
||||
help_text="0 表示使用 provider 默认值。",
|
||||
)
|
||||
connect_timeout_seconds = models.PositiveIntegerField(default=30)
|
||||
extra_body = models.JSONField(default=dict, blank=True)
|
||||
is_active = models.BooleanField(default=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
connect_timeout_seconds = models.PositiveIntegerField("连接超时秒数", default=30)
|
||||
extra_body = models.JSONField("额外请求体", default=dict, blank=True)
|
||||
is_active = models.BooleanField("启用", default=True)
|
||||
created_at = models.DateTimeField("创建时间", auto_now_add=True)
|
||||
updated_at = models.DateTimeField("更新时间", auto_now=True)
|
||||
|
||||
class Meta:
|
||||
db_table = "ai_model"
|
||||
@@ -88,20 +90,21 @@ class AiModel(models.Model):
|
||||
|
||||
class ModelAlias(models.Model):
|
||||
class OperationType(models.TextChoices):
|
||||
TITLE = "title", "Generate title"
|
||||
IMAGE = "image", "Generate image"
|
||||
TITLE = "title", "生成标题"
|
||||
IMAGE = "image", "生成图片"
|
||||
|
||||
alias = models.SlugField(max_length=64)
|
||||
operation_type = models.CharField(max_length=32, choices=OperationType.choices)
|
||||
alias = models.SlugField("能力别名", max_length=64)
|
||||
operation_type = models.CharField("操作类型", max_length=32, choices=OperationType.choices)
|
||||
ai_model = models.ForeignKey(
|
||||
AiModel,
|
||||
verbose_name="AI 模型",
|
||||
on_delete=models.PROTECT,
|
||||
related_name="aliases",
|
||||
)
|
||||
is_default = models.BooleanField(default=False)
|
||||
is_active = models.BooleanField(default=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
is_default = models.BooleanField("默认别名", default=False)
|
||||
is_active = models.BooleanField("启用", default=True)
|
||||
created_at = models.DateTimeField("创建时间", auto_now_add=True)
|
||||
updated_at = models.DateTimeField("更新时间", auto_now=True)
|
||||
|
||||
class Meta:
|
||||
db_table = "model_alias"
|
||||
@@ -142,28 +145,29 @@ class ModelAlias(models.Model):
|
||||
|
||||
class AiConfigAuditLog(models.Model):
|
||||
class TargetType(models.TextChoices):
|
||||
AI_MODEL = "ai_model", "AI model"
|
||||
MODEL_ALIAS = "model_alias", "Model alias"
|
||||
AI_MODEL = "ai_model", "AI 模型"
|
||||
MODEL_ALIAS = "model_alias", "能力别名"
|
||||
|
||||
class Action(models.TextChoices):
|
||||
CREATE = "create", "Create"
|
||||
UPDATE = "update", "Update"
|
||||
DELETE = "delete", "Delete"
|
||||
CREATE = "create", "创建"
|
||||
UPDATE = "update", "更新"
|
||||
DELETE = "delete", "删除"
|
||||
|
||||
actor = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
verbose_name="操作人",
|
||||
null=True,
|
||||
blank=True,
|
||||
on_delete=models.SET_NULL,
|
||||
related_name="+",
|
||||
)
|
||||
action = models.CharField(max_length=16, choices=Action.choices)
|
||||
target_type = models.CharField(max_length=32, choices=TargetType.choices)
|
||||
target_id = models.PositiveBigIntegerField(null=True, blank=True)
|
||||
target_repr = models.CharField(max_length=255)
|
||||
changed_fields = models.JSONField(default=list, blank=True)
|
||||
changes = models.JSONField(default=dict, blank=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
action = models.CharField("动作", max_length=16, choices=Action.choices)
|
||||
target_type = models.CharField("目标类型", max_length=32, choices=TargetType.choices)
|
||||
target_id = models.PositiveBigIntegerField("目标 ID", null=True, blank=True)
|
||||
target_repr = models.CharField("目标描述", max_length=255)
|
||||
changed_fields = models.JSONField("变更字段", default=list, blank=True)
|
||||
changes = models.JSONField("变更内容", default=dict, blank=True)
|
||||
created_at = models.DateTimeField("创建时间", auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = "ai_config_audit_log"
|
||||
|
||||
Reference in New Issue
Block a user