【问题标题】:Struggling to see the utility of custom Django Model Managers努力查看自定义 Django 模型管理器的实用性
【发布时间】:2021-08-28 07:35:45
【问题描述】:

我没有这个问题的任何代码,所以这将更多地是关于客户经理的实用性,而不是实施问题。

我已阅读文档、许多博客文章并尝试自己实现一些,但我在 Django 自定义模型管理器中找不到该实用程序。我知道他们可以帮助分段代码并可以帮助 DRY 原则,但我很难看到如何。所以这个问题可以分解成几个小点

  • 这对 DRY 原则有何帮助?
  • 这对代码分段有何帮助?
  • viewsmodel 方法无法做到的管理人员可以做什么?

【问题讨论】:

    标签: django django-models django-managers


    【解决方案1】:

    您可以在管理器中封装过滤、注释、子查询等。例如:

    class ActiveManager(models.Manager):
    
        def get_queryset(self, *args, **kwargs):
            return super().get_queryset(*args, **kwargs).filter(
                active=True
            )

    然后将其应用于具有active 字段的模块:

    class MyActiveModel(models.Model):
        active = models.BooleanField(default=False)
    
        objects = ActiveManager()

    现在如果我们使用MyActiveModel.objects.all(),它只会检索active = True 的记录。因此我们不需要在所有视图中应用此过滤,我们可以像在任何模型中一样使用objects,它会透明地过滤对象。

    如果您想对查询集进行扩展,也经常使用Manager

    例如我们可以定义一个AuthorQuerySet,它提供了一个额外的方法.of_user(…),例如保留给定用户是作者的记录,或者用户是超级用户,检索所有记录:

    class AuthorQuerySet(models.QuerySet):
    
        def from_user(self, user):
            if user.is_superuser:
                return self
            else:
                return self.filter(author=user)

    然后与允许执行此过滤的经理合作:

    from django.conf import settings
    
    class Post(models.Model):
        author = models.ForeignKey(
            settings.AUTH_USER_MODEL,
            on_delete=models.CASCADE,
        )
    
        objects = AuthorQuerySet.as_manager()

    然后我们可以检索用户可以看到的对象:

    Post.objects<strong>.filter_user(myuser)</strong>

    或在过滤器链中执行此操作:

    Post.objects.filter(title__istartswith='The').<strong>filter_user(myuser)</strong>

    因此它主要处理封装逻辑,例如过滤、注释等只定义一次,然后以透明的方式在视图中使用。换句话说,视图不必担心它只会检索活动对象,管理器会处理这个问题。

    这对代码分段有何帮助?

    模型专注于在数据库中存储记录并呈现数据。通常它应该决定你在什么情况下看到什么记录。 views 用于此目的。但是如果逻辑相同,那么在视图中编写它是没有意义的,因为如果(几乎)总是应该发生的过滤、注释等被复制到一个大量的意见。通过在管理器中实现这一点,我们在模型和视图之间有一个层,可以始终以相同的方式过滤、注释等数据。

    管理者可以做哪些视图或模型方法不能做的事情?

    可以对每个视图重复一次相同的过滤代码,但这使得以后在流程中很难更改该逻辑,因为那时应该查看这些模型在哪些视图中被访问,并更改all 这些观点。这样很容易忽略某些内容,从而导致状态不一致。

    还可以在模型中定义静态方法来进行过滤。但是相同的模型可以与多个经理一起使用,这样,根据情况,选择另一个模型。

    换句话说,它是模型和视图之间的一层,它与模型以多对一的方式工作,与视图代码以多对多的方式工作。

    【讨论】:

    • 只是为了确认一下,这行代码Post.objects.filter_user(myuser)理论上会替换Post.objects.filter(author=username)之类的东西?我的另一个问题是 - 这不是有点限制吗?我知道你可以有多个不同名字的经理,所以你能做类似object_author = AuthorObjectFilter()或类似的事情,然后objects=defaultusermanager吗?
    • @jeremy_lord:是的,虽然在这个答案中我们首先检查用户并仅在它不是超级用户时才过滤,因此您可以将更复杂的逻辑封装在管理器中,然后在多个视图。如果您稍后认为它可能会更改,这可能很有用(例如,除了超级用户或作者之外,作者的经理也可以看到这一点)。因此,您只需定义一次逻辑,然后在视图中重用它。
    • 感谢您这么快的回复!你太快了,我想你可能错过了我所做的编辑哈哈如果你能查看我评论的后半部分,那就太好了,谢谢!
    【解决方案2】:

    我将尝试简要回答您的问题,为其他评论者留下更深入的答案空间。也没有代码。

    这对 DRY 原则有何帮助?

    通常,特别是在大型项目中,您将拥有一组在代码中广泛(重)使用的查询。例如,获取用户的购物清单或获取一些带有注释字段的帐户元数据。如果将这些查询保留在自定义模型管理器中,您可以:

    • 在一个地方定义它们并在任何其他地方重复使用
    • 在一个地方修改它们的功能,而无需关心搜索和修改实际使用管理器方法(查询)的地方

    基本上,遵循这一原则(在您的情况下使用自定义管理器),您可以降低需要操作的代码库的复杂性。

    这对代码分段有何帮助?

    您所有与查询相关的内容都存在于适当模型的管理器中 - 您不会将表示和业务逻辑以及整个代码库中的一些实用程序弄乱。 Manager 方法对其消费者一无所知,消费者也不需要了解这些方法的实现。

    管理者可以做哪些视图或模型方法不能做的事情?

    使用管理器,您可以更改返回的查询集,这将是每个消费者的默认更改。此外,谈到管理器与模型,存在语义差异:假设模型的方法专门针对模型实例保存的数据或与任何模型实例相关的数据进行操作,其中管理器对任何非特定实体(但模型相同)进行操作.可以把它想象成“模型方法对表行做一些事情,而管理器对表行做一些事情”。

    【讨论】:

    • 这绝对有助于我理解管理器和一般语义,所以谢谢你。我将等待更多答案,然后接受一个作为答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-20
    • 1970-01-01
    • 1970-01-01
    • 2013-05-12
    • 1970-01-01
    相关资源
    最近更新 更多