国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當(dāng)前位置: 首頁 - 科技 - 知識百科 - 正文

使用Python裝飾器在Django框架下去除冗余代碼的教程

來源:懂視網(wǎng) 責(zé)編:小采 時間:2020-11-27 14:39:40
文檔

使用Python裝飾器在Django框架下去除冗余代碼的教程

使用Python裝飾器在Django框架下去除冗余代碼的教程:Python裝飾器是一個消除冗余的強(qiáng)大工具。隨著將功能模塊化為大小合適的方法,即使是最復(fù)雜的工作流,裝飾器也能使它變成簡潔的功能。 例如讓我們看看Django web框架,該框架處理請求的方法接收一個方法對象,返回一個響應(yīng)對象: def handle_r
推薦度:
導(dǎo)讀使用Python裝飾器在Django框架下去除冗余代碼的教程:Python裝飾器是一個消除冗余的強(qiáng)大工具。隨著將功能模塊化為大小合適的方法,即使是最復(fù)雜的工作流,裝飾器也能使它變成簡潔的功能。 例如讓我們看看Django web框架,該框架處理請求的方法接收一個方法對象,返回一個響應(yīng)對象: def handle_r

Python裝飾器是一個消除冗余的強(qiáng)大工具。隨著將功能模塊化為大小合適的方法,即使是最復(fù)雜的工作流,裝飾器也能使它變成簡潔的功能。

例如讓我們看看Django web框架,該框架處理請求的方法接收一個方法對象,返回一個響應(yīng)對象:

def handle_request(request):
 return HttpResponse("Hello, World")

我最近遇到一個案例,需要編寫幾個滿足下述條件的api方法:

  • 返回json響應(yīng)
  • 如果是GET請求,那么返回錯誤碼
  • 做為一個注冊api端點(diǎn)例子,我將會像這樣編寫:

    def register(request):
     result = None
     # check for post only
     if request.method != 'POST':
     result = {"error": "this method only accepts posts!"}
     else:
     try:
     user = User.objects.create_user(request.POST['username'],
     request.POST['email'],
     request.POST['password'])
     # optional fields
     for field in ['first_name', 'last_name']:
     if field in request.POST:
     setattr(user, field, request.POST[field])
     user.save()
     result = {"success": True}
     except KeyError as e:
     result = {"error": str(e) }
     response = HttpResponse(json.dumps(result))
     if "error" in result:
     response.status_code = 500
     return response
    

    然而這樣我將會在每個api方法中編寫json響應(yīng)和錯誤返回的代碼。這將會導(dǎo)致大量的邏輯重復(fù)。所以讓我們嘗試用裝飾器實(shí)現(xiàn)DRY原則吧。

    裝飾器簡介

    如果你不熟悉裝飾器,我可以簡單解釋一下,實(shí)際上裝飾器就是有效的函數(shù)包裝器,python解釋器加載函數(shù)的時候就會執(zhí)行包裝器,包裝器可以修改函數(shù)的接收參數(shù)和返回值。舉例來說,如果我想要總是返回比實(shí)際返回值大一的整數(shù)結(jié)果,我可以這樣寫裝飾器:

    # a decorator receives the method it's wrapping as a variable 'f'
    def increment(f):
     # we use arbitrary args and keywords to
     # ensure we grab all the input arguments.
     def wrapped_f(*args, **kw):
     # note we call f against the variables passed into the wrapper,
     # and cast the result to an int and increment .
     return int(f(*args, **kw)) + 1
     return wrapped_f # the wrapped function gets returned.
    

    現(xiàn)在我們就可以用@符號和這個裝飾器去裝飾另外一個函數(shù)了:

    @increment
    def plus(a, b):
     return a + b
     
    result = plus(4, 6)
    assert(result == 11, "We wrote our decorator wrong!")
    

    裝飾器修改了存在的函數(shù),將裝飾器返回的結(jié)果賦值給了變量。在這個例子中,'plus'的結(jié)果實(shí)際指向increment(plus)的結(jié)果。

    對于非post請求返回錯誤

    現(xiàn)在讓我們在一些更有用的場景下應(yīng)用裝飾器。如果在django中接收的不是POST請求,我們用裝飾器返回一個錯誤響應(yīng)。

    def post_only(f):
     """ Ensures a method is post only """
     def wrapped_f(request):
     if request.method != "POST":
     response = HttpResponse(json.dumps(
     {"error": "this method only accepts posts!"}))
     response.status_code = 500
     return response
     return f(request)
     return wrapped_f
    

    現(xiàn)在我們可以在上述注冊api中應(yīng)用這個裝飾器:

    @post_only
    def register(request):
     result = None
     try:
     user = User.objects.create_user(request.POST['username'],
     request.POST['email'],
     request.POST['password'])
     # optional fields
     for field in ['first_name', 'last_name']:
     if field in request.POST:
     setattr(user, field, request.POST[field])
     user.save()
     result = {"success": True}
     except KeyError as e:
     result = {"error": str(e) }
     response = HttpResponse(json.dumps(result))
     if "error" in result:
     response.status_code = 500
     return response
    

    現(xiàn)在我們就有了一個可以在每個api方法中重用的裝飾器。

    發(fā)送json響應(yīng)

    為了發(fā)送json響應(yīng)(同時處理500狀態(tài)碼),我們可以新建另外一個裝飾器:

    def json_response(f):
     """ Return the response as json, and return a 500 error code if an error exists """
     def wrapped(*args, **kwargs):
     result = f(*args, **kwargs)
     response = HttpResponse(json.dumps(result))
     if type(result) == dict and 'error' in result:
     response.status_code = 500
    return response
    

    現(xiàn)在我們就可以在原方法中去除json相關(guān)的代碼,添加一個裝飾器做為代替:

    post_only
    @json_response
    def register(request):
     try:
     user = User.objects.create_user(request.POST['username'],
     request.POST['email'],
     request.POST['password'])
     # optional fields
     for field in ['first_name', 'last_name']:
     if field in request.POST:
     setattr(user, field, request.POST[field])
     user.save()
     return {"success": True}
     except KeyError as e:
     return {"error": str(e) }
    

    現(xiàn)在,如果我需要編寫新的方法,那么我就可以使用裝飾器做冗余的工作。如果我要寫登錄方法,我只需要寫真正相關(guān)的代碼:

    @post_only
    @json_response
    def login(request):
     if request.user is not None:
     return {"error": "User is already authenticated!"}
     user = auth.authenticate(request.POST['username'], request.POST['password'])
     if user is not None:
     if not user.is_active:
     return {"error": "User is inactive"}
     auth.login(request, user)
     return {"success": True, "id": user.pk}
     else:
     return {"error": "User does not exist with those credentials"}
    

    BONUS: 參數(shù)化你的請求方法

    我曾經(jīng)使用過Tubogears框架,其中請求參數(shù)直接解釋轉(zhuǎn)遞給方法這一點(diǎn)我很喜歡。所以要怎樣在Django中模仿這一特性呢?嗯,裝飾器就是一種解決方案!

    例如:

    def parameterize_request(types=("POST",)):
     """
     Parameterize the request instead of parsing the request directly.
     Only the types specified will be added to the query parameters.
     
     e.g. convert a=test&b=cv in request.POST to
     f(a=test, b=cv)
     """
     def wrapper(f):
     def wrapped(request):
     kw = {}
     if "GET" in types:
     for k, v in request.GET.items():
     kw[k] = v
     if "POST" in types:
     for k, v in request.POST.items():
     kw[k] = v
     return f(request, **kw)
     return wrapped
     return wrapper
    

    注意這是一個參數(shù)化裝飾器的例子。在這個例子中,函數(shù)的結(jié)果是實(shí)際的裝飾器。

    現(xiàn)在我就可以用參數(shù)化裝飾器編寫方法了!我甚至可以選擇是否允許GET和POST,或者僅僅一種請求參數(shù)類型。

    @post_only
    @json_response
    @parameterize_request(["POST"])
    def register(request, username, email, password,
     first_name=None, last_name=None):
     user = User.objects.create_user(username, email, password)
     user.first_name=first_name
     user.last_name=last_name
     user.save()
     return {"success": True}
    

    現(xiàn)在我們有了一個簡潔的、易于理解的api。

    BONUS #2: 使用functools.wraps保存docstrings和函數(shù)名

    很不幸,使用裝飾器的一個副作用是沒有保存方法名(__name__)和docstring(__doc__)值:

    def increment(f):
     """ Increment a function result """
     wrapped_f(a, b):
     return f(a, b) + 1
     return wrapped_f
     
    @increment
    def plus(a, b)
     """ Add two things together """
     return a + b
     
    plus.__name__ # this is now 'wrapped_f' instead of 'plus'
    plus.__doc__ # this now returns 'Increment a function result' instead of 'Add two things together'
    

    這將對使用反射的應(yīng)用造成麻煩,比如Sphinx,一個 自動生成文檔的應(yīng)用。

    為了解決這個問題,我們可以使用'wraps'裝飾器附加上名字和docstring:

    from functools import wraps
     
    def increment(f):
     """ Increment a function result """
     @wraps(f)
     wrapped_f(a, b):
     return f(a, b) + 1
     return wrapped_f
     
    @increment
    def plus(a, b)
     """ Add two things together """
     return a + b
     
    plus.__name__ # this returns 'plus'
    plus.__doc__ # this returns 'Add two things together'
    

    BONUS #3: 使用'decorator'裝飾器

    如果仔細(xì)看看上述使用裝飾器的方式,在包裝器聲明和返回的地方也有不少重復(fù)。

    你可以安裝python egg 'decorator',其中包含一個提供裝飾器模板的'decorator'裝飾器!

    使用easy_install:

    $ sudo easy_install decorator
    

    或者Pip:

    $ pip install decorator
    

    然后你可以簡單的編寫:


    from decorator import decorator
     
    @decorator
    def post_only(f, request):
     """ Ensures a method is post only """
     if request.method != "POST":
     response = HttpResponse(json.dumps(
     {"error": "this method only accepts posts!"}))
     response.status_code = 500
     return response
     return f(request)
    

    這個裝飾器更牛逼的一點(diǎn)是保存了__name__和__doc__的返回值,也就是它封裝了 functools.wraps的功能!

    聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

    使用Python裝飾器在Django框架下去除冗余代碼的教程

    使用Python裝飾器在Django框架下去除冗余代碼的教程:Python裝飾器是一個消除冗余的強(qiáng)大工具。隨著將功能模塊化為大小合適的方法,即使是最復(fù)雜的工作流,裝飾器也能使它變成簡潔的功能。 例如讓我們看看Django web框架,該框架處理請求的方法接收一個方法對象,返回一個響應(yīng)對象: def handle_r
    推薦度:
    標(biāo)簽: python 框架 Django
    • 熱門焦點(diǎn)

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 欧日韩一区二区三区 | 欧美精品啪啪 | 欧美激情91| 久久91精品国产91久久跳舞 | 亚洲色图 欧美 | 欧美日韩中字 | 成人国产一区二区三区精品 | 免费成人毛片 | 一区二区三区成人 | 久久99国产精品成人欧美 | 日本一区二区三区在线观看 | 一本综合久久国产二区 | 亚洲欧美日韩另类在线专区 | 欧美午夜在线 | 国产高清在线播放免费观看 | 99久久精品免费国产一区二区三区 | 国产短视频精品一区二区三区 | 在线v片 | 欧美日本中文字幕 | 久久久久久久一精品 | 亚洲欧美日本在线 | 91精品久久久久久久久网影视 | 久久国产热| 亚洲青草 | 欧美日韩亚洲另类 | 国产精品乱码一区二区三区 | 亚洲国产精久久久久久久 | 精品欧美一区二区三区精品久久 | 99视频在线| 亚洲欧美天堂 | 美女牲交视频一级毛片 | 亚洲国产成人精品一区二区三区 | 国产精品电影一区二区 | 日韩电影免费在线观看视频 | 国产最新网站 | 日韩视频在线播放 | 国产精品第1页在线观看 | 久久精品国产三级不卡 | 免费一看一级毛片 | 国产精品va一级二级三级 | 唯美清纯另类亚洲 |