大多数Pythonic/Django在运行时动态加载客户端库的方法

大多数Pythonic/Django在运行时动态加载客户端库的方法,python,django,oop,design-patterns,django-rest-framework,Python,Django,Oop,Design Patterns,Django Rest Framework,我正在编写一个Django应用程序,其中我们将有多个客户端库来调用第三方API。我们希望能够在调用不同端点时确定在运行时加载哪个客户端库。我正在尝试确定最适合Django/python的方法来实现这一点 当前的想法是将类名存储在模型字段中,在视图中查询模型,然后将类名传递给服务工厂,服务工厂实例化相关服务并进行查询。我还考虑编写一个使用反射来查询类名的模型方法 例如,假设我们有一个名为Exchange的模型,它有一个id、一个名称,并存储客户机名称 class Exchange(models.M

我正在编写一个Django应用程序,其中我们将有多个客户端库来调用第三方API。我们希望能够在调用不同端点时确定在运行时加载哪个客户端库。我正在尝试确定最适合Django/python的方法来实现这一点

当前的想法是将类名存储在模型字段中,在视图中查询模型,然后将类名传递给服务工厂,服务工厂实例化相关服务并进行查询。我还考虑编写一个使用反射来查询类名的模型方法

例如,假设我们有一个名为Exchange的模型,它有一个id、一个名称,并存储客户机名称

class Exchange(models.Model):
    exchange_name = models.CharField(max_length=255)
    client_name = models.CharField(max_length=255)

    def __str__(self):
        return self.exchange_name
那么在视图中,我们可能会有类似的内容:

from rest_framework.views import APIView
from MyProject.trades.models import Exchange
from django.http import Http404
from MyProject.services import *


class GetLatestPrice(APIView):

    def get_object(self, pk):
        try:
            exchange = Exchange.objects.get(pk=pk)
        except Exchange.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        exchange = self.get_objectt(pk)
        service = service_factory.get_service(exchange.client_name)
        latest_price = service.get_latest_price()
        serializer = PriceSerializer(latest_price)
        return Response(serializer.data)
这种语法可能并不完美,但尚未经过测试。但我们的想法是,也许我们有

ExchangeA - client1 
ExchangeB - client2
ExchangeC - client3
对于每个客户机,我们都有一个服务类,它们都继承自同一个抽象基。每个服务都有一个完全相同的覆盖。这样,当您调用/api/get_latest_price时,您可以将Exchange id作为查询参数传递,代码将加载任何与服务和客户端库相关的内容。这将使我们能够轻松地向系统添加新类型,具有一致的小视图,并解耦业务逻辑。这是一种可接受的、可伸缩的pythonic方法吗?还是有更好的解决方案?本质上,问题是在django中实现多态性,并将域模型与数据模型分离。这是一个必须解决的问题,所以我很好奇其他人会怎么做。我知道像这样调用第三方API是不寻常的,但由于我们被迫这样做,我希望以最干净、最具可扩展性的方式来实现;博士

没有银弹

更有用的答案:

没有通用的、方便的方法来解决你的问题。根据客户端库和第三方API的实现,解决方案可能会有很大的不同。如果它们都相似,你可以使用你的方法,你会很好。如果API有一些差异,例如,一个API没有端点来获取最新价格,那么您需要找到一些解决方法。如果API在工作流中有一些很大的差异,您将需要找到完全不同的方法,例如,如果一个API可以立即返回报告,而另一个API将在5分钟后通过回调返回报告,您将需要找到解决方法

因此,我可以给你一个真正的建议,就是检查第三方API之间的差异,并更多地关注你自己项目的最高抽象的设计,这将使用低级别的客户端库。尽量减少第三方之间的差异对项目的影响。

TL;博士

没有银弹

更有用的答案:

没有通用的、方便的方法来解决你的问题。根据客户端库和第三方API的实现,解决方案可能会有很大的不同。如果它们都相似,你可以使用你的方法,你会很好。如果API有一些差异,例如,一个API没有端点来获取最新价格,那么您需要找到一些解决方法。如果API在工作流中有一些很大的差异,您将需要找到完全不同的方法,例如,如果一个API可以立即返回报告,而另一个API将在5分钟后通过回调返回报告,您将需要找到解决方法


因此,我可以给你一个真正的建议,就是检查第三方API之间的差异,并更多地关注你自己项目的最高抽象的设计,这将使用低级别的客户端库。尽量减少第三方之间的差异对您的项目的影响。

我们在这里有类似的情况(以及其他一些密切相关的情况),并且完全使用这种模式:在模型中存储“服务”类的名称,并使用一些注册表(您的“服务工厂”)来获取该类。It JustWorks(tm),没有人(来自加入并最终离开的各种开发人员)抱怨过这种设计,也没有人提出更好的解决方案,到目前为止,我们遇到的唯一一个小麻烦是处理仍然从数据库中引用的“中断”服务(这也不是火箭科学)

FWIW,这主要是“策略”设计模式的变体,我真的无法想象一个更好的(对于“更好”=“更简单、更有效、更易于维护”)解决方案来满足这一需求

编辑


请注意,我上面的回答假设
Exchange
具有您的问题中未提及的其他责任-否则,正如Alexandr Zayets所述,此模型似乎没有什么用处;-)

我们在这里有一个类似的情况(以及其他一些密切相关的情况),并且完全使用这种模式:在模型中存储“服务”类的名称,并使用一些注册表(您的“服务工厂”)来获取该类。It JustWorks(tm),没有人(来自加入并最终离开的各种开发人员)抱怨过这种设计,也没有人提出更好的解决方案,到目前为止,我们遇到的唯一一个小麻烦是处理仍然从数据库中引用的“中断”服务(这也不是火箭科学)

FWIW,这主要是“策略”设计模式的变体,我真的无法想象一个更好的(对于“更好”=“更简单、更有效、更易于维护”)解决方案来满足这一需求

编辑

请注意,我上面的回答假设
Exchange
具有您的问题中未提及的其他责任-否则,正如Alexandr Zayets所述,此模型似乎没有什么用处;-)

完全不相关,但不要使用通配符导入(=>“来自MyProject.services import*”)-它们使代码无法维护,并且很容易出现中断/完全意外的行为。总是直截了当