迭代字典时动态设置类属性(模型字段)

时间:2013-03-17 13:16:30

标签: python django django-models python-2.7

我试图根据字典中包含的键,值对动态定义模型的字段。

我尝试过两种方式:

字典是:

NOTIFICATION_TYPES = {
    'friend_request_received': 0,
    'friend_request_accepted': 1,
    # eccetera
}

非常错误(因为未定义self而生成异常):

class EmailNotification(models.Model):
    """
    User Email Notification Model
    Takes care of tracking the user's email notification preferences
    """
    user = models.OneToOneField(User, verbose_name=_('user'))

    for key, value in NOTIFICATION_TYPES.items():
        setattr(self, key, models.BooleanField(_('notify new matches'), default=True))

    class Meta:
        db_table = 'profile_email_notification'

显然错误但不会创建模型字段:

class EmailNotification(models.Model):
    """
    User Email Notification Model
    Takes care of tracking the user's email notification preferences
    """
    user = models.OneToOneField(User, verbose_name=_('user'))

    def __init__(self, *args, **kwargs):

        for key, value in NOTIFICATION_TYPES.items():
            setattr(self.__class__, key, models.BooleanField(_(key), default=True))

        super(EmailNotification, self).__init__(*args, **kwargs)

    class Meta:
        db_table = 'profile_email_notification'

我可以做我想做的事情吗?我确定是的!

3 个答案:

答案 0 :(得分:1)

在定义类之后,您需要设置的额外属性:

class EmailNotification(models.Model):
    """
    User Email Notification Model
    Takes care of tracking the user's email notification preferences
    """
    user = models.OneToOneField(User, verbose_name=_('user'))

    class Meta:
        db_table = 'profile_email_notification'


for key, value in NOTIFICATION_TYPES.items():
    setattr(EmailNotification, key, models.BooleanField(_('notify new matches'), default=True))

您可以使用class decorator将for循环包装到应用于类的函数中:

def add_notification(cls):
    for key, value in NOTIFICATION_TYPES.items():
        setattr(cls, key, models.BooleanField(_('notify new matches'), default=True))
    return cls

@add_notification
class EmailNotification:
    # ...

我有点担心Django元类处理会想要处理这些字段,您可能需要添加其他调用以使EmailNotification._meta结构知道您添加的其他字段。

答案 1 :(得分:1)

您可以使用类装饰器:

def add_notification(cls):
    for key in NOTIFICATION_TYPES:
        setattr(cls, key, models.BooleanField(_('notify new matches'), default=True))
    return cls

@add_notification
class EmailNotification(models.Model):
    """
    User Email Notification Model
    Takes care of tracking the user's email notification preferences
    """
    user = models.OneToOneField(User, verbose_name=_('user'))

    class Meta:
        db_table = 'profile_email_notification'

答案 2 :(得分:0)

感谢答案中的建议,但有一个关键缺失的概念。

必须做两件事:

setattr(myclass, key, field)
myclass.add_to_class(key, field)

这里有一个有效的解决方案:

https://github.com/nemesisdesign/nodeshot/blob/7798f81d558791499039afab1c860483fe30dd77/nodeshot/community/notifications/models/user_settings.py#L6