【问题标题】:Design models: search by singleton models in django设计模型:在 django 中按单例模型搜索
【发布时间】:2017-07-24 08:17:32
【问题描述】:

我有一个模型TranslationService,它有一些字段和方法应该被每个新服务覆盖。我有三个服务:Google、Azure、Bing,它们是系统中唯一的(我们只有一个 Google 服务和一个 Azure 服务等)。我需要执行这样的操作:TranslationService.objects.filter(service_name=service_name)

但如果我将TranslationService 设为抽象,我将无法遍历 abst 类,因为它不是在 DB 中创建的。如果我进行继承,我应该在模型之类的代码中实现覆盖方法的逻辑,然后通过控制台创建GoogleService。这是唯一的方法还是我可以减少通过控制台创建对象。

如何设计我的模型以在 translation_services 中执行搜索?

class TranslationService(models.Model):
 created_at = models.DateTimeField(auto_now_add=True)
 updated_at = models.DateTimeField(auto_now=True)
 service_name = models.CharField(max_length=40)
 base_url = models.CharField(max_length=255)
 api_version = models.FloatField()

 def get_step_translation(self, pk, lang, lesson):
    pass

 def create_step_translation(self, pk, lang, type):
    pass

class GoogleTranslator(TranslationService):
 base_url = "https://google.com"
 service_name = "Google"
 api_version = 1.5

 def get_step_translation(self, pk, lang, lesson, **kwargs):
  ... some logic
 def create_step_translation(self, pk, lang, type):
  ... some logic

【问题讨论】:

    标签: python django inheritance design-patterns django-models


    【解决方案1】:

    我认为模型继承在这里是错误的方法。一个模型类代表一个数据库表,你的对象都存在于同一个表中,所以它们应该是同一个模型。

    您可以只在 if 语句中包含每个翻译方法的逻辑,但我理解您为什么要将其抽象出来。那么,如何将所有操作委托给一个单独的服务类呢?您可以覆盖 __getattr__ 来设置服务并委托方法。

    class GoogleTranslation(object):
        def __init__(self, obj):
            self.obj = obj
        def get_step_translation(self, pk, lang, lesson):
            print('google, {}, {}, {}'.format(pk, lang, lesson))
            ... logic goes here...
        def create_step_translation(self, pk, lang, type):
            ...
    
    class TranslationService(models.Model):
        created_at = models.DateTimeField(auto_now_add=True)
        updated_at = models.DateTimeField(auto_now=True)
        service_name = models.CharField(max_length=40)
        base_url = models.CharField(max_length=255)
        api_version = models.FloatField()
    
        services = {
             'google': GoogleTranslation,
             'bing': BingTranslation,
        }
    
        @property
        def service(self):
            if not hasattr(self, '_service'):
                # create a new Service object and pass it this model instance
                self._service = self.services[self.service_name](self)
            return self._service
    
        def __getattr__(self, name):
            if name == '_service':
                raise AttributeError   # the service hasn't been instantiated yet
            # delegate all unknown lookups to the service object
            return getattr(self.service, name)
    

    现在您可以通过 gs = TranslationService.objects.get(service_name='google') 获取 Google 实例并执行 gs.get_step_translation(1, '2', '3') 或其他操作,该方法调用将委托给 GoogleTranslation 实例。

    【讨论】:

    • 当你调用get_step_translation时,一开始在TranslationService里面找不到它,然后调用__getattr__,它调用了GoogleTranslation里面的方法。我说的对吗?
    • 是的,正确的。事实上,如果只有这两种方法可以委托,这可能有点过于复杂了;您可以在 TranslationService 中明确定义这两个,并让它们在 self.service 上调用相同的方法。但如果你有很多方法,这种模式会更好。
    • 唯一的问题是“从 GoogleTranslation 访问 TranslationService 字段”。就像我不能从GoogleTranslationself.base_url 范围的原因
    • 你可以使用self.obj.base_url
    猜你喜欢
    • 2014-03-17
    • 2021-08-29
    • 2015-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-07
    相关资源
    最近更新 更多