首页 > 解决方案 > Django - 将代理模型简化为单个类

问题描述

我的数据库中有用户表,它们可以是活动的或非活动的。如果我只想查询活动用户,我会定义一个如下所示的代理模型。

class User(models.Model):
    name        = models.CharField(max_length=50)
    location    = models.CharField(max_length=50)
    active      = models.BooleanField()


class UserActive(models.Manager):
    def get_queryset(self):
        return super(UserActive, self).get_queryset().filter(active=True)

class ActiveUser(User):
    objects = UserActive()
    class Meta:
        proxy = True

然后通过使用 ActiveUser,我可以只对活动用户进行计算/统计。

问题是,我需要同时定义 UserActive 和 ActiveUser 类,这对我来说似乎很尴尬。因为对于每个主类(在本例中是 User),我们需要定义另外两个类。想象一下我们还有其他几个模型需要实现 Proxy,代码看起来会很乱。我可以知道我们是否可以有更优雅的方式?

谢谢亚历克斯

标签: djangodjango-models

解决方案


我真的会避免覆盖.objects管理器,并将其用作某种隐式过滤。Python之显式优于隐式,通过使用ActiveUser,你基本上实现了一个过滤管理器,但是像整个集合一样提出它。

也许更优雅的解决方案是定义多个管理器。所以我们可以构造一个过滤管理器装饰器:

def filter_manager(**kwargs):
    def decorator(klass):
        def get_queryset(self):
            return super(klass, self).get_queryset().filter(**kwargs)
        klass.get_queryset = get_queryset
        return klass
    return decorator

然而,这个装饰器会丢弃get_queryset在管理器本身上定义的 a,所以你不能用它执行额外的补丁。

现在我们可以用一种相当优雅的方式定义一些管理器:

@filter_manager(active=True)
class ActiveManager(models.Manager):
    pass

@filter_manager(active=False)
class InactiveManager(models.Manager):
    pass

最后,我们可以将这些管理器添加到User模型中,并使用明确的名称

class User(models.Model):
    name        = models.CharField(max_length=50)
    location    = models.CharField(max_length=50)
    active      = models.BooleanField()

    objects = models.Manager()
    active_users = ActiveManager()
    inactive_users = InactiveManager()

所以现在我们可以User.active_users用来查询活跃用户。因此,我们没有代理模型,并且可以使用User.active_users.count()例如查询(我们可以执行所有操作,例如 with.objects但然后 for .active_users


推荐阅读