【问题标题】:Refactor method which use django queries to not violate DRY?重构使用 django 查询不违反 DRY 的方法?
【发布时间】:2017-02-28 15:21:51
【问题描述】:

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

  1. 一个数据库散列(随机的非实例唯一性,db_hash=True
  2. 对象名称(“John”或“Sam”为name=True
  3. 对象的 ID。 (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。

【问题讨论】:

  • 只能有一个是真的吗?

标签: python django refactoring django-queryset dry


【解决方案1】:

你可以这样做:

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

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

【讨论】:

  • 在查询键中应该是 'db_hash' 而不是 'hash'。我无法编辑你的答案,因为我的编辑太小了。
  • 感谢 erhesto,已修复。
【解决方案2】:

如果你足够勇敢,你可以把它做成一个过滤器的包装器,

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

【讨论】:

    猜你喜欢
    • 2016-07-30
    • 1970-01-01
    • 2010-11-01
    • 2013-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多