今天在修改之前做的一个搜索接口,虽然使用了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...


二十一
1.4k 声望867 粉丝

无论遇到多大的困难,你总是能扛过去,坚持一件事,对自己