如何让Django Manager和Model的交互遵循开闭原则?

问题描述 投票:0回答:1

我正在为我的 Django 应用程序设计模型,并且关心将调用者的逻辑与模型的实现解耦,以便将来对模型本身的更改不需要在代码库的下游进行更改。简而言之 遵守开闭原则 (OCP)

我想知道在最好地利用 Django 框架的同时实现这一点的最佳实践是什么。

从概念上讲,我相信执行以下操作是有意义的:

from django.db import models

class FooManager(models.Manager):
    def is_active(self):
        return self.filter(is_active=True)

class Foo(models.Model):
    _bar = models.CharField(max_length=100, db_column="bar")
    is_active = models.BooleanField(default=True)

    objects = FooManager()

    @property
    def bar(self):
        return self._bar
    
    @bar.setter
    def bar(self, value):
        if not self._bar:
            self._bar = value
        else:
            #some setter logic
            pass
  1. 查询逻辑的自定义管理器 对于每个模型,定义了一个自定义管理器,负责处理模型上的各种过滤逻辑。例如。呼叫者将呼叫

    Foo.objects.filter(is_active=True)
    ,而不是呼叫
    Foo.objects.is_active()
    。将来,如果 is_active 的实现逻辑发生变化,调用者无需更改其逻辑,保持 OCP。

  2. 模型字段的封装 对于模型中的每个字段,为 getter 和 setter 定义了

    @property
    ,允许更改底层模型字段。

  3. 最小耦合 耦合仅保留在自定义管理器和模型上。

我对这种方法的主要担忧

对于第1点: 要求将所有过滤逻辑定义为自定义管理器中的方法可能会导致每个管理器有数十个方法(由于字段的组合),从而难以管理。

对于第2点: 虽然在调用模型属性时很方便,例如

Foo.bar
,使用管理器时需要调用底层字段。例如
Foo.objects.filter(bar=x)
不起作用,需要使用
Foo.objects.filter(_bar=x)
。该要求破坏了第 2 点的理由,除非第 1 点也得到实施。

问题

  1. 这种方法是在 Django 中实现解耦同时遵守开放/封闭原则的良好实践吗?

  2. Django 生态系统中是否有更好或更标准的方法来解耦模型逻辑和调用者逻辑,而不引入不必要的复杂性?

  3. 经验丰富的 Django 开发人员如何处理字段封装,同时确保查询保持直观和可维护?

谢谢您的帮助!

django django-models solid-principles
1个回答
0
投票

模型可能不是正确的层。事实上,您可以进行 自定义查找 [Django-doc]自定义模型字段 [Django-doc] 使 ORM 语言更加“直观”。在某种程度上,这就是 Django 所做的事情,例如

URLField
model 字段[Django-doc]:在幕后,它只是一个带有额外逻辑的
VARCHAR

我们可以对 URL 字段进行自定义查找以提取架构,例如:

from django.db.models import CharField, Transform, URLField, Value
from django.db.models.functions import StrIndex, Substr


@URLField.register_lookup
class SchemaTransform(Transform):
    lookup_name = 'schema'
    output_field = models.CharField()

    def as_sql(self, compiler, connection):
        return Substr(
            self.lhs, Value(1), StrIndex(self.lhs, Value(':')) - Value(1)
        ).as_sql(compiler, connection)

例如过滤器:

unsafe_urls = MyModel.objects.filter(url_field__schema='http')
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.