乐趣区

django中的cachedproperty

今天在修改之前做的一个搜索接口, 虽然使用了 haystack, 但是由于需要修改请求参数和响应数据格式, 所以大费周折调试了老一会儿, 问题是这样的, 大家如果有好的点子可以留言哦:

haystack 默认的请求接口为

.../search?q= 搜索关键字 &models=xxxx.xxxx&models=xxxx.xxxx

我设计的接口

.../search?q= 搜索关键字 &f= 搜索类型

我们的项目分为搜索全部及类型搜索, 所以像默认的接口太暴露, 所以我设计的短小干练了点, 但是怎样去实现, 看源码我实现了第一版:

class KaokaoSearchView(SearchView):
    def __call__(self, request):
        type = int(request.GET.get('f', 0))

        models = {
            0: 'xxx.xxxxx',
            1: 'xx.xxxxx',
            2: 'xxxxxx.xxxxxxxxx'
        }

        data = request.GET
        _mutable = data._mutable
        data._mutable = True
        data['models'] = models.get(type, '')
        data._mutable = _mutable
        self.request = request

但是问题来了, 多个 model 搜索怎样实现? 我反正首先是进行照葫芦画瓢:

models = {
            0: 'xxx.xxxxx',
            1: 'xx.xxxxx',
            2: 'xxxxxx.xxxxxxxxx',
            9: 'xxx.xxxx&xx.xxxxx&xxxxxx.xxxxxxxxx'
        }

结果是这样的:

而正确的应该是这样的:

原来 models 需要的是一个 list, 这好办

models = {
            0: 'xxx.xxxxx',
            1: 'xx.xxxxx',
            2: 'xxxxxx.xxxxxxxxx',
            9: ['xxx.xxxx', 'xx.xxxxx', 'xxxxxx.xxxxxxxxx']
        }

出现了这种情况:


list 嵌套? 该怎么办呢? 继续我的小聪明

data['models'] = models.get(type, '')
data['models'] = data['models'][0][1] + data['models'][0][1] + data['models'][0][2]


acc? 什么鬼
原来此时的 models 还没有形成 list 嵌套, 而是一个上面定义的 list, 也就说明我们的操作在了嵌套之前, 怎么解决呢? 那就看 Django 请求的完整过程吧, 看看啥时候操作了这个东西 …

结果

在 django 源码中:WSGIRequest 中 GET 操作了这个 query_string, 源码是这样的:

class WSGIRequest(http.HttpRequest):
    def __init__(self, environ):
        ...
    @cached_property
    def GET(self):
        # The WSGI spec says 'QUERY_STRING' may be absent.
        raw_query_string = get_bytes_from_wsgi(self.environ, 'QUERY_STRING', '')
        return http.QueryDict(raw_query_string, encoding=self._encoding)

这个 QueryDict 将请求路径中的 ’xxx.xxxx&xx.xxxxx&xxxxxx.xxxxxxxxx’, 变成了

<QueryDict: {u'xxx': [u'xxxx'], u'xx': [u'xxxxx'], u'xxxxxx': [u'xxxxxxxxx']}>

那这样就好办了

models = {
            0: 'models=xxx.xxxxx',
            1: 'models=xx.xxxxx',
            2: 'models=xxxxxx.xxxxxxxxx',
            9: 'models=xxx.xxxx&models=xx.xxxxx&models=xxxxxx.xxxxxxxxx'
        }
data = request.GET
_mutable = data._mutable
data._mutable = True
data['models'] = http.QueryDict(models.get(type, ''))
data._mutable = _mutable
self.request = request

顺利解决!!! 不知道大家看到在 Django 源码中的 GET 方法中有一个装饰器 @cached_property, 这是什么东西呢?

# 源码
class cached_property(object):
    """
    Decorator that converts a method with a single self argument into a
    property cached on the instance.

    Optional ``name`` argument allows you to make cached properties of other
    methods. (e.g.  url = cached_property(get_absolute_url, name='url') )
    """
    def __init__(self, func, name=None):
        self.func = func
        self.__doc__ = getattr(func, '__doc__')
        self.name = name or func.__name__

    def __get__(self, instance, cls=None):
        if instance is None:
            return self
        res = instance.__dict__[self.name] = self.func(instance)
        return res

这怎么起到 cached 的作用呢? 大家认为的缓存应该都是用 redis 或这 mongoDB 这种数据库吧, 如果你已经从事开发很长时间, 请一定要去看这个东西: 曾经我也写过一篇文章, 今天拿出来, 有需要的可以点开 https://segmentfault.com/a/11…

退出移动版