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?我是不是错过了一些简单的东西?

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

我认为您可以使用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))

最新更新