Inner Classes - Inheriting and Overriding Their Attributes

I am trying to understand how Django uses python metaclasses for its database models (parameters) and came up with the following code snippet, which should roughly imitate Django logic.

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'

Using the code above, I expect the following output:

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

Instead, I get the following exception

>>> 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'

My question is: why User.DbMetadoesn't the attribute inherit migratefrom Model.DbMeta? Is there any solution for this kind of problem?

Edit

According to Daniel, I came up with the following that worked for me:

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)
+4
source share
1 answer

This is not a question of inner classes.

- . , __dict__ of Model.DbMeta " " "", User.DbMeta " ", , .

dir(); , , DatabaseOptions, __dict__.

+1

Source: https://habr.com/ru/post/1691689/


All Articles