【问题标题】:Abstract Django model manager抽象 Django 模型管理器
【发布时间】:2014-02-07 19:35:52
【问题描述】:

我在这里缺乏 Python 元编程知识。假设我有以下内容:

class OwnCompanyManager(models.Manager):
    """Only companies of this user"""
    def get_queryset(self, user):
        if user.is_superuser:
            return super(OwnCompanyManager, self).get_queryset()
        return super(OwnCompanyManager, self).get_queryset().filter(
            companyuser__user=user)


class OwnPublisherManager(models.Manager):
    """Only publishers of this user's company"""
    def get_queryset(self, user):
        if user.is_superuser:
            return super(OwnPublisherManager, self).get_queryset()
        return super(OwnPublisherManager, self).get_queryset().filter(
            company__companyuser__user=user)

class Company(models.Model):
    name = models.CharField(max_length=45)

    objects = models.Manager()
    own = OwnCompanyManager()


class Publisher(models.Model):
    company = models.ForeignKey(Company)
    allow_latest_dev = models.BooleanField(default=False)
    domains_blocked = models.BooleanField(default=False)

    objects = models.Manager()
    own = OwnPublisherManager()

我还有很多。我不喜欢复制粘贴样板Own(Publisher|Company|Etcetra)Manager)。如您所见,唯一的变化是在过滤器中。

如何从CompanyPublisher等模型中抽象出Own(InsertModelNameHere)Manager并使用它?我想在管理器定义中指定过滤器 kwargs。

【问题讨论】:

    标签: python django django-models metaprogramming


    【解决方案1】:

    这里不需要元编程或任何特别聪明的东西。您只需要提取更改的位。在这种情况下,它只是filter 的参数:您可以使用参数传递的字典形式,并将过滤器作为字符串存储在类属性中。

    class AbstractManager(models.Manager):
        def get_queryset(self, user):
            if user.is_superuser:
                return super(AbstractManager, self).get_queryset()
            return super(AbstractManager, self).get_queryset().filter(**{self.filter: user})
    
    class OwnCompanyManager(AbstractManager):
        filter = "companyuser__user"
    
    class OwnPublisherManager(AbstractManager):
        filter = "company__companyuser__user"
    

    【讨论】:

    • 这看起来更好。但是,是否有可能拥有 AbstractManager 而没有其他类? IE。在模型定义中构造Manager类?
    【解决方案2】:

    受丹尼尔回复的启发:

    class OwnManager(models.Manager):
        def __init__(self, key):
            super(OwnManager, self).__init__()
            self.k = key
    
        def get_queryset(self, user):
            if user.is_superuser:
                return super(OwnManager, self).get_queryset()
            return super(OwnManager, self).get_queryset().filter(**{self.k: user})
    
    
    class Company(models.Model):
        name = models.CharField(max_length=45)
    
        objects = models.Manager()
        own = OwnManager("companyuser__user")
    
    
    class Publisher(models.Model):
        company = models.ForeignKey(Company)
        allow_latest_dev = models.BooleanField(default=False)
        domains_blocked = models.BooleanField(default=False)
    
        objects = models.Manager()
        own = OwnManager("company__companyuser__user")
    

    这样我不想为每个模型创建愚蠢的类。

    谢谢丹尼尔。

    【讨论】: