2017-02-28 49 views
0

我写了一个用已知的查找类型查询模型。表示输入类型被传递为kwargs的标志。下面解释kwarg查找以及传入的kwargs。使用django查询不违反DRY的重构方法?

  1. 数据库散列(随机没有独特的情况下,与db_hash=True)中的对象(“约翰”或“山姆”作为name=True
  2. ID的对象的
  3. 名称。 (obj.ids 124,或134id=True
  4. 的情况下(OBJ文件没有任何标志)

例如只为名称的方法调用会是什么样子,

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。

+0

只能有一个kwargs为真? –

回答

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**字典扩展语法。

(注意,我不知道你的查询都是正确的,这些都检查两个路径和驱动程序相匹配的价值,这似乎是它并不一定是真实的。)

+0

在查询键中它应该是'db_hash'而不是'hash'。由于编辑太小,我无法编辑您的答案。 – erhesto

+0

谢谢erhesto,修复。 –

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")