修复了兼容层存在的一些显著问题
This commit is contained in:
@@ -352,14 +352,7 @@ class FieldExpressionDescriptor:
|
||||
|
||||
class QModelBase(models.base.ModelBase):
|
||||
def __new__(mcs, name, bases, namespace, **kwargs):
|
||||
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
|
||||
# 不再强制设置 db_column —— Django 会自动处理
|
||||
|
||||
# 动态设置 managed:子服务器可设 GVSDSDK_MANAGE_TABLES=True 让 gvsdsdk 管理表
|
||||
meta = namespace.get('Meta')
|
||||
@@ -373,40 +366,70 @@ class QModelBase(models.base.ModelBase):
|
||||
|
||||
cls = super().__new__(mcs, name, bases, namespace, **kwargs)
|
||||
|
||||
# 模型创建后,自动为所有字段添加描述符,支持 Model.field_name 链式 OOP
|
||||
# 模型创建后,包装字段描述符以支持类级别 FieldExpression
|
||||
if not cls._meta.abstract:
|
||||
_attach_field_descriptors(cls)
|
||||
_wrap_field_descriptors(cls)
|
||||
|
||||
return cls
|
||||
|
||||
|
||||
def _attach_field_descriptors(cls: Type) -> None:
|
||||
"""为 QModel 子类的所有字段自动添加 FieldExpressionDescriptor / ForeignKeyIdDescriptor,
|
||||
使 Model.field_name 在类级别访问时返回 FieldExpression,支持链式 OOP 查询。"""
|
||||
from django.db import models as dj_models
|
||||
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,
|
||||
)
|
||||
|
||||
for field in cls._meta.local_fields:
|
||||
fname = field.name
|
||||
# 跳过已有描述符或内部属性
|
||||
if fname.startswith('_'):
|
||||
continue
|
||||
# 检查是否已有同名描述符(避免覆盖手动定义的)
|
||||
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))
|
||||
|
||||
original_desc = cls.__dict__.get(fname)
|
||||
if original_desc is None:
|
||||
continue
|
||||
|
||||
if isinstance(field, (dj_models.ForeignKey, dj_models.OneToOneField)):
|
||||
# FK 字段:类级别访问返回 FieldExpression,实例级别访问返回关联对象
|
||||
setattr(cls, fname, ForeignKeyIdDescriptor(fname))
|
||||
# 只包装已知的 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)
|
||||
else:
|
||||
setattr(cls, fname, FieldExpressionDescriptor(fname))
|
||||
# 普通字段(DeferredAttribute)没有 __set__,直接写 __dict__
|
||||
obj.__dict__[self._field_name] = value
|
||||
|
||||
|
||||
class QModel(models.Model, metaclass=QModelBase):
|
||||
|
||||
Reference in New Issue
Block a user