Django Queryset - 复杂关系参数作为变量?

时间:2012-01-19 21:09:00

标签: django django-queryset

我有一个用于邻近搜索的地理对象。该对象通过各种路径键入不同的其他对象。

示例:

  blog.geo_object
  user.profile.geo_object
  group.event.geo_object

现在,我做一个边界框搜索,其字符串如下:

radius_queryset = base_queryset.filter(
    user__profile__geo__lat__gte = bounding_box.lat_min,
    user__profile__geo__lat__lte = bounding_box.lat_max,
    user__profile__geo__lon__gte = bounding_box.lon_min,
    user__profile__geo__lon__lte = bounding_box.lon_max,

然后在其他对象上:

radius_queryset = base_queryset.filter(
    blog__geo__lat__gte = bounding_box.lat_min,
    blog__geo__lat__lte = bounding_box.lat_max,
    blog__geo__lon__gte = bounding_box.lon_min,
    blog__geo__lon__lte = bounding_box.lon_max,
)

这遵循以下一般格式:

radius_queryset = base_queryset.filter(
    [lookup_path]__geo__lat__gte = bounding_box.lat_min,
    [lookup_path]__geo__lat__lte = bounding_box.lat_max,
    [lookup_path]__geo__lon__gte = bounding_box.lon_min,
    [lookup_path]__geo__lon__lte = bounding_box.lon_max,
)
# where lookup_path = "blog"  or "user__profile" in the two above examples

我正在编写足够的这些内容(目前为止还有3个,更多内容)想要概括查询 - 封装是可维护性的好朋友,也是打击错误的好伙伴。

所以,对于我的问题:没有使用exec和eval(看起来很难看),有没有办法让过滤器参数名称变为sub-in变量?我在这里错过了一些简单的东西吗?

2 个答案:

答案 0 :(得分:4)

**kwargs是你的答案!

def generate_qs(lookup_path, bounding_box):
    return base_queryset.filter(**{
        lookup_path + '__geo__lat__gte' : bounding_box.lat_min,
        lookup_path + '__geo__lat__lte' : bounding_box.lat_max,
        lookup_path + '__geo__lon__gte' : bounding_box.lon_min,
        lookup_path + '__geo__lon__lte' : bounding_box.lon_max,
    })

radius_queryset = generate_qs('blog', bounding_box)

答案 1 :(得分:0)

我认为你可以使用Python的**kwargs语法将这种肮脏的东西放在辅助函数中。类似的东西:

def helper(lookup_path, bounding_box):
        return dict([ ("%s__geo__%s" % (lookup_path, lkup_left, ),
                       getattr(bounding_box, lkup_right), )
                     for lkup_left, lkup_right in
                     (("lat__gte", "lat_min", ),
                      ("lat__lte", "lat_max", ),
                      ("lon__gte", "lon_min", ),
                      ("lon__lte", "lon_max", ), 
                     ) ])

qs = base_queryset.filter(**helper(lookup_path, bounding_box))