使用django查询不违反DRY的重构方法?

时间:2017-02-28 15:21:51

标签: python django refactoring django-queryset dry

我写了一个查询具有已知查找类型的模型。表示输入类型作为kwargs传递的标志。 kwarg查找与下面的kwargs一起解释如下。

  1. 数据库哈希(对于db_hash=True
  2. 实例的随机数并非唯一。)
  3. 对象的名称(" John"或" Sam" as name=True
  4. 对象的ID。 (obj.ids 124134id=True
  5. 实例(没有任何标志的objs)
  6. 例如,仅用于方法调用的名称,

    self.check_all_routes("Sam", "452", name=True)
    

    我想重构以下方法,以减少它在违反DRY时产生的混乱。

    def check_all_routes(self, driver, route, **kwargs):
        _hash = kwargs.get('db_hash')
        _name = kwargs.get('name')
        _id = kwargs.get('id')
    
        if _hash:
            return self.model.objects.filter(
                driver__db_hash=driver,
                route__db_hash=route
            ).prefetch_related().select_related().values_list('route_number')
        if _name:
            return self.model.objects.filter(
                driver__name=driver,
                route__name=route
            ).prefetch_related().select_related().values_list('route_number')
        if _id:
            return self.model.objects.filter(
                driver_id=driver,
                route_id=route
            ).prefetch_related().select_related().values_list('route_number')
    
        return self.model.objects.filter(
            driver=driver,
            route=route
        ).prefetch_related().select_related().values_list('route_number')
    

    可以做些什么来使它不会违反DRY。

2 个答案:

答案 0 :(得分:5)

你可以这样做:

def check_all_routes(self, driver, route, **kwargs):
    queries = {
        "db_hash": ['driver__db_hash', 'route__db_hash'],
        "name": ['driver__name', 'route__name'],
        "id": ['driver_id', 'route_id'],
        "default": ['driver', 'route']
    }
    arg = next((k for k, v in kwargs.items() if v), 'default')
    params = queries[arg]
    query = dict(zip(params, [driver, route]))
    return self.model.objects.filter(**query).prefetch_related().select_related().values_list('route_number')

这有点神奇,但最重要的部分是建立一个字典,然后使用filter dict扩展语法传递给**

(注意,我不确定你的查询是否正确;这些都检查路由和驱动程序是否匹配值,这似乎不一定是真的。)

答案 1 :(得分:0)

如果你足够勇敢,你可以使它成为过滤器的包装器,

def check_all_routes(self, **kwargs):
    return self.model.objects.filter(
        **kwargs
    ).prefetch_related().select_related().values_list('route_number')

所以不要传递

self.check_all_routes("Sam", "452", name=True)

你可以做到

self.check_all_routes(driver__name="Sam", route__name="452")

您不需要提供类型的地方。这样做的一个优点是可以混合使用类型。

self.check_all_routes(driver__name="Sam", route__db_hash="some%hash%string")