? 這就算是第一篇博客了,我老大陳如杰(一個牛逼的程序員)講過,只有自己研究了的東西才能寫到博客上,我謹遵教誨。

??

? 環境:Django==1.8.2、django-tastypie==0.12.2-dev、redis==2.10.3、django-redis==4.1.0

? django配置了使用redis作為后臺緩存

? 在ubuntu中安裝了redis-server(sudo apt-get install redis-server),在django的settings中加入如下配置:(具體可以參考http://niwinz.github.io/django-redis/latest/)

cachenet可以刪除嗎,??

#?to?set?django's?default?cache?add?by?minkedong
CACHES?=?{"default":?{"BACKEND":?"django_redis.cache.RedisCache","LOCATION":?"redis://127.0.0.1:6379/1","OPTIONS":?{"CLIENT_CLASS":?"django_redis.client.DefaultClient",}}
}

在寫tastypie自己的ModelResource時,在Meta中加入:

cache?=?SimpleCache(timeout=8*60*60)

? 當我請求此ModelResource的時候,發出GET請求“/api/v1/author/1/”后,在ubuntu的bash中使用命令:redis-cli -n 1 進入redis,在redis中鍵入命令:keys *,查看到已經緩存了此API的請求結果。

? 但當我發出GET請求"/api/v1/author/"后,進入redis查看,發現并沒有緩存我的結果。

? 果斷進入tastypie的源碼查看,在"tastypie.resources.ModelResource"中有如下兩個方法:

????def?get_list(self,?request,?**kwargs):"""Returns?a?serialized?list?of?resources.Calls?``obj_get_list``?to?provide?the?data,?then?handles?that?resultset?and?serializes?it.Should?return?a?HttpResponse?(200?OK)."""#?TODO:?Uncached?for?now.?Invalidation?that?works?for?everyone?may?be#???????impossible.base_bundle?=?self.build_bundle(request=request)objects?=?self.obj_get_list(bundle=base_bundle,?**self.remove_api_resource_names(kwargs))sorted_objects?=?self.apply_sorting(objects,?options=request.GET)paginator?=?self._meta.paginator_class(request.GET,?sorted_objects,?resource_uri=self.get_resource_uri(),?limit=self._meta.limit,?max_limit=self._meta.max_limit,?collection_name=self._meta.collection_name)to_be_serialized?=?paginator.page()#?Dehydrate?the?bundles?in?preparation?for?serialization.bundles?=?[]for?obj?in?to_be_serialized[self._meta.collection_name]:bundle?=?self.build_bundle(obj=obj,?request=request)bundles.append(self.full_dehydrate(bundle,?for_list=True))to_be_serialized[self._meta.collection_name]?=?bundlesto_be_serialized?=?self.alter_list_data_to_serialize(request,?to_be_serialized)return?self.create_response(request,?to_be_serialized)def?get_detail(self,?request,?**kwargs):"""Returns?a?single?serialized?resource.Calls?``cached_obj_get/obj_get``?to?provide?the?data,?then?handles?that?resultset?and?serializes?it.Should?return?a?HttpResponse?(200?OK)."""basic_bundle?=?self.build_bundle(request=request)try:obj?=?self.cached_obj_get(bundle=basic_bundle,?**self.remove_api_resource_names(kwargs))except?ObjectDoesNotExist:return?http.HttpNotFound()except?MultipleObjectsReturned:return?http.HttpMultipleChoices("More?than?one?resource?is?found?at?this?URI.")bundle?=?self.build_bundle(obj=obj,?request=request)bundle?=?self.full_dehydrate(bundle)bundle?=?self.alter_detail_data_to_serialize(request,?bundle)return?self.create_response(request,?bundle)

使用pdb打斷點,發現“/api/v1/author/1/”請求調用get_detail方法,而"/api/v1/author/"請求調用get_list方法,從源碼中不難看出,get_detail中調用了cached_obj_get方法,其從cache中拿數據,而get_list調用了obj_get_list方法(源碼中有cached_obj_get_list方法,其并未調用),即未從cache中拿數據(其實get_list方法的注釋中已經給出了解釋

文件夾cache?# TODO: Uncached for now. Invalidation that works for everyone may be impossible.),好吧,那解決方式就比較簡單了,直接在自己的ModelResource中覆蓋掉此方法,更改成:

???def?get_list(self,?request,?**kwargs):"""Returns?a?serialized?list?of?resources.Calls?``obj_get_list``?to?provide?the?data,?then?handles?that?resultset?and?serializes?it.Should?return?a?HttpResponse?(200?OK)."""#?TODO:?Uncached?for?now.?Invalidation?that?works?for?everyone?may?be#???????impossible.base_bundle?=?self.build_bundle(request=request)objects?=?self.cached_obj_get_list(bundle=base_bundle,?**self.remove_api_resource_names(kwargs))sorted_objects?=?self.apply_sorting(objects,?options=request.GET)paginator?=?self._meta.paginator_class(request.GET,?sorted_objects,?resource_uri=self.get_resource_uri(),?limit=self._meta.limit,?max_limit=self._meta.max_limit,?collection_name=self._meta.collection_name)to_be_serialized?=?paginator.page()#?Dehydrate?the?bundles?in?preparation?for?serialization.bundles?=?[]for?obj?in?to_be_serialized[self._meta.collection_name]:bundle?=?self.build_bundle(obj=obj,?request=request)bundles.append(self.full_dehydrate(bundle,?for_list=True))to_be_serialized[self._meta.collection_name]?=?bundlesto_be_serialized?=?self.alter_list_data_to_serialize(request,?to_be_serialized)return?self.create_response(request,?to_be_serialized)

再次請求"/api/v1/author/"后,發現redis中已經緩存了此結果!


但是,這里面后面的實際請求會有一個問題,那就是當你請求“/api/v1/author/”和請求“/api/v1/author/?format=json&name=jack”(假設有name篩選參數),其返回的json數據都是全量的數據,為什么呢?因為他在redis中生成的cache key都是一樣的,我們要針對不同的請求參數生成不同的cache key,相當于不同的請求參數也cache一份數據。我的做法如下,直接在自己的ModelResource中覆蓋掉cached_obj_get_list方法,更改成:


def?cached_obj_get_list(self,?bundle,?**kwargs):"""更改get_list的cache?key,使其對不同參數存不同的cache?key"""if?hasattr(bundle.request,?'GET'):#?Grab?a?mutable?copy.filters?=?bundle.request.GET.copy()filters.update(kwargs)applicable_filters?=?self.build_filters(filters=filters)applicable_str?=?':'.join(sorted(["%s=%s"?%?(key,?','.join(value)?if?type(value)?==?type([])?else?value,?)?for?key,?value?in?applicable_filters.items()]))cache_key?=?self.generate_cache_key('list',?applicable_str,?**kwargs)obj_list?=?self._meta.cache.get(cache_key)if?obj_list?is?None:obj_list?=?self.obj_get_list(bundle=bundle,?**kwargs)self._meta.cache.set(cache_key,?obj_list)return?obj_list


drop_caches無法修改為0,因為對redis的機制不太了解,后面自己將研究一下redis的東西,有什么錯誤,歡迎大家指正!