【问题标题】:Inner classes - Inheritance and overriding their attributes内部类 - 继承和覆盖它们的属性
【发布时间】:2023-03-13 15:21:01
【问题描述】:

我试图了解 Django 如何将 python 的元类用于其数据库模型(选项),并提出了以下精简代码 sn-p,它应该大致模仿 Django 的逻辑。

class DatabaseOptions(object):

    def __init__(self, opts):
        if opts:
            for key, val in opts.__dict__.items():
                if not key.startswith('__') and not callable(val):
                    setattr(self, key, val)


class MetaModel(type):

    def __new__(cls, name, bases, classdict):
        result = super().__new__(cls, name, bases, dict(classdict))

        opts = classdict.pop('DbMeta', None)
        if opts:
            setattr(result, '_db_meta', DatabaseOptions(opts))

        return result


class Model(object, metaclass=MetaModel):

    class DbMeta:
        database = 'default'
        migrate = True


class User(Model):

    class DbMeta(Model.DbMeta):
        database = 'user'


class GroupUser(User):

    class DbMeta(User.DbMeta):
        database = 'group_user'

使用上面的代码,我希望得到以下输出:

print(Model._db_meta.database)  # default
print(Model._db_meta.migrate)  # True

print(User._db_meta.database)  # user
print(User._db_meta.migrate)   # True

print(GroupUser._db_meta.database)  # group_user
print(GroupUser._db_meta.migrate)  # True

相反,我得到以下异常

>>> python3 test.py 
default
True
user
Traceback (most recent call last):
  File "test.py", line 48, in <module>
    print(User._db_meta.migrate)   # True
AttributeError: 'DatabaseOptions' object has no attribute 'migrate'

我的问题是为什么User.DbMeta 不从Model.DbMeta 继承migrate 属性?这类问题有解决办法吗?

编辑

根据丹尼尔的回答,我想出了以下对我有用的方法:

class DatabaseOptions(object):

    def __init__(self, opts):
        if opts:
            for key in dir(opts):
                if not key.startswith('__'):
                    val = getattr(opts, key, None)
                    if not callable(val):
                        setattr(self, key, val)

【问题讨论】:

    标签: python django python-3.x django-models


    【解决方案1】:

    这不是专门针对内部类的问题。

    类属性就是类本身的属性。因此,Model.DbMeta__dict__ 包含“database”和“migrate”,但 User.DbMeta 的一个包含 only“database”,因为这是该类定义的唯一属性。

    然而,那些属性dir()显示的;您可能应该迭代在 DatabaseOptions 中的类上调用它的结果,而不是 __dict__

    【讨论】:

    • 谢谢你,丹尼尔。我已经完全监督了这个问题。使用 dir() 成功了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-11
    • 1970-01-01
    相关资源
    最近更新 更多