From 2479a878c526c0d524f4073360302f6f39fec66a Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 17 Jun 2026 04:02:07 +0800 Subject: [PATCH] revert f252fc2aff3749ae3e832a86e06f0010d78cc5eb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit revert 修复了兼容层存在的一些显著问题 时间上无法容忍,暂且先恢复到这个版本重新进入生产状态 --- gvsdsdk/model_base.py | 81 ++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 52 deletions(-) diff --git a/gvsdsdk/model_base.py b/gvsdsdk/model_base.py index 190d52a..015f36e 100644 --- a/gvsdsdk/model_base.py +++ b/gvsdsdk/model_base.py @@ -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):