Django-将代理模型简化为单个类

时间:2018-07-12 09:03:04

标签: django django-models

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

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的模型,代码看起来很凌乱。我可以知道我们是否可以有更优雅的方式吗?

谢谢 亚历克斯

2 个答案:

答案 0 :(得分:2)

我真的会避免覆盖.objects管理器,并将其用作某种隐式过滤。 Python的 Zen 优于 explicit优于隐式,通过使用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,因此您无法对此进行额外的修补。

现在,我们可以以一种非常优雅的方式定义一些经理:

@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()进行查询(好吧,我们可以像执行.objects一样执行所有操作,但是可以执行.active_users

答案 1 :(得分:0)

我创建了一个只有用户模型的新Django项目。我的models.py看起来像这样

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models

# Create your models here.

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


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

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

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

当我尝试User.objects.all()时。

错误:type object 'User' has no attribute 'objects'