revert 修复了兼容层存在的一些显著问题
时间上无法容忍,暂且先恢复到这个版本重新进入生产状态
This commit is contained in:
2026-06-17 04:02:07 +08:00
parent 461643079b
commit 2479a878c5

View File

@@ -296,7 +296,14 @@ class _CastJsonExpression:
class QModelBase(models.base.ModelBase):
def __new__(mcs, name, bases, namespace, **kwargs):
# 不再强制设置 db_column —— Django 会自动处理
from django.db import models as dj_models
for attr_name, attr_val in list(namespace.items()):
if isinstance(attr_val, dj_models.Field) and not attr_val.db_column:
# ForeignKey/OneToOneField 的数据库列名是 attr_name + '_id'
if isinstance(attr_val, (dj_models.ForeignKey, dj_models.OneToOneField)):
attr_val.db_column = attr_name + '_id'
else:
attr_val.db_column = attr_name
# 动态设置 managed子服务器可设 GVSDSDK_MANAGE_TABLES=True 让 gvsdsdk 管理表
meta = namespace.get('Meta')
@@ -310,70 +317,40 @@ class QModelBase(models.base.ModelBase):
cls = super().__new__(mcs, name, bases, namespace, **kwargs)
# 模型创建后,包装字段描述符支持类级别 FieldExpression
# 模型创建后,自动为所有字段添加描述符支持 Model.field_name 链式 OOP
if not cls._meta.abstract:
_wrap_field_descriptors(cls)
_attach_field_descriptors(cls)
return cls
def _wrap_field_descriptors(cls: Type) -> None:
"""包装 Django 字段描述符,使类级别访问返回 FieldExpression
实例级别完全委托给 Django 原生描述符。
Django 的字段描述符DeferredAttribute / ForwardManyToOneDescriptor
- __get__(None, cls) → 返回字段对象本身(类级别)
- __get__(instance, cls) → 返回字段值(实例级别)
我们包装后:
- __get__(None, cls) → 返回 FieldExpression类级别用于链式 OOP
- __get__(instance, cls) → 委托给原生描述符(实例级别,正常行为)
"""
from django.db.models.query_utils import DeferredAttribute
from django.db.models.fields.related_descriptors import (
ForwardManyToOneDescriptor,
ForwardOneToOneDescriptor,
)
def _attach_field_descriptors(cls: Type) -> None:
"""为 QModel 子类的所有字段自动添加 FieldExpressionDescriptor / ForeignKeyIdDescriptor
使 Model.field_name 在类级别访问时返回 FieldExpression支持链式 OOP 查询。"""
from django.db import models as dj_models
for field in cls._meta.local_fields:
fname = field.name
# 跳过已有描述符或内部属性
if fname.startswith('_'):
continue
original_desc = cls.__dict__.get(fname)
if original_desc is None:
# 检查是否已有同名描述符(避免覆盖手动定义的)
existing = cls.__dict__.get(fname)
if isinstance(existing, (FieldExpressionDescriptor, ForeignKeyIdDescriptor)):
continue
# 跳过 Django 自动创建的反向关系和 id 主键(如果用户未显式定义)
if fname == 'id' and field.primary_key and not isinstance(
cls.__dict__.get(fname), (FieldExpressionDescriptor, ForeignKeyIdDescriptor)
):
# id 字段也添加描述符
setattr(cls, fname, FieldExpressionDescriptor(fname))
continue
# 只包装已知的 Django 描述符类型
if isinstance(original_desc, (DeferredAttribute, ForwardManyToOneDescriptor,
ForwardOneToOneDescriptor)):
wrapper = _FieldExpressionWrapper(original_desc, cls, fname)
setattr(cls, fname, wrapper)
class _FieldExpressionWrapper:
"""包装 Django 字段描述符,类级别返回 FieldExpression实例级别委托给原生描述符。"""
def __init__(self, original_descriptor, model_class, field_name):
self._original = original_descriptor
self._model = model_class
self._field_name = field_name
self._has_set = hasattr(original_descriptor, '__set__')
def __get__(self, obj, objtype=None):
if obj is None:
# 类级别访问:返回 FieldExpression
return FieldExpression(self._model, self._field_name)
# 实例级别访问:委托给原生 Django 描述符
return self._original.__get__(obj, objtype)
def __set__(self, obj, value):
if self._has_set:
# FK/O2O 描述符有 __set__
self._original.__set__(obj, value)
if isinstance(field, (dj_models.ForeignKey, dj_models.OneToOneField)):
# FK 字段:类级别访问返回 FieldExpression实例级别访问返回关联对象
setattr(cls, fname, ForeignKeyIdDescriptor(fname))
else:
# 普通字段DeferredAttribute没有 __set__直接写 __dict__
obj.__dict__[self._field_name] = value
setattr(cls, fname, FieldExpressionDescriptor(fname))
class QModel(models.Model, metaclass=QModelBase):