django中的@cached_property

今天在修改之前做的一個搜索接口,雖然使用了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'
        }

結果是這樣的:

clipboard.png

而正確的應該是這樣的:

clipboard.png

原來models需要的是一個list,這好辦

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

出現了這種情況:

clipboard.png
list嵌套?該怎麼辦呢?繼續我的小聰明

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

clipboard.png
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...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章