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