我很长时间都在努力解决这个问题。我搜索并搜索了整个互联网的解决方案,但没有什么是可以接受的。
简而言之,请回应丹尼尔的评论:
我想使用Django的Active Record ORM对象,但只能作为DTO,能够将数据保存回数据库,包括复杂的关系。 这样,我的业务对象将独立于它的数据源,并且它们只包含行为。
长版:
我们开始了一个项目,在所需的业务逻辑方面看起来很简单,所以我选择了Django作为一个框架,使事情变得更容易。问题变得复杂,也许实现将在更大的项目中使用,所以我想将业务对象对象与activerecord分离,并且我想仅将django用作数据库后端以及使用我的对象的东西。 UI已经从开始分离,它只调用django后端提供的REST API。
我的一个例子问题: 我有一个Request模型,它连接到许多其他模型。此请求包含一些与网络相关的需求规范。这些网络与云模型相关联。云下的网络将连接到从请求生成的预留(当前它们连接到请求的nw描述符以确定查询期间的配置)。
class Request(Model):
... # bunch_of_stuff_here
class NetworkDescriptor(Model):
request = ForeignKey(Request)
configA = ...
configB = ...
class Cloud(Model):
...
class Network(Model):
cloud = ForeignKey(Cloud)
used_by = ForeignKey(NetworkDescriptor)
我考虑过的解决方案:
1)将模型嵌入BO并委托给他们。 这会导致以下问题:当我尝试访问云的网络并简单地委派时,例如使用
def get_networks:
return orm_dto.networks
我找回AR对象,这很糟糕。我不想在这里泄露AR细节。我必须编写一个从ORMNetworks到BOnetworks的映射器,它跟踪网络( network.used_by=request )
的变化。这个定义了一个Object Mapper ...我已经拥有(即ORM),我不想要这个。 :)
2)嵌入模型但只允许高级别的交互。这听起来更像面向对象,但仍然不知道如何做到这一点:
class Cloud:
def serve_request(bo_request):
???
结果应该是一堆网络,其中used_by字段设置为BORequest参数后面的ORMRequest对象。我该如何获得这些信息?如果我不想泄漏ORM细节,那么......我必须写一些跟踪BO对象并可以将它们映射到AR对象的东西,例如:
class Cloud:
def serve_request(bo_request):
for net in self._find_matching_networks(bo_requsets)
net.used_by = repo.get_ar_from_bo(bo_request)
这又是......不是最好的解决方案,因为我必须编写映射器,但在这种情况下,它似乎更容易,因为我不必处理相关字段。
3)使用模板方法模式,使AR对象只是一个数据源。
class Request(Model, Resource):
def get_cpu():
return self._cpu
class Resource(object)
def __le__(self, other:Resource):
return self.get_cpu() <= other.get_cpu()
这又是一个我不喜欢的解决方案,因为在这种情况下AR仍然是BO。我无法在不到达数据库的情况下有效地对其进行单元测试,但至少在代码级别,业务部分与数据访问部分是分开的。
4)完全交换到SqlAlchemy。问题是通过Django管理AR对象比使用炼金术更容易,但也许这是最终的解决方案。