Django-rest-framework: etagを簡単に远加/怜蚌したす。

䜜成日 2011幎06月29日  Â·  24コメント  Â·  ゜ヌス: encode/django-rest-framework

Djangoには玠晎らしいetag / condition / last_modifiedデコレヌタがありたす。 drfクラスベヌスのビュヌでは、「get」を装食できないため、機胜したせん。 getはhttp応答ではないオブゞェクトを返すため、応答にetagヘッダヌを远加する方法はありたせん。

drf内からこれを行う方法を知りたいです。 リ゜ヌスのオヌバヌラむド可胜なメ゜ッド、たたはetagを生成するために䜿甚できるビュヌたたはミックスむンに沿った䜕かを考えおいたす。

djangoでそれを行うもう1぀の方法は、ミドルりェアを䜿甚するこずですが、デコレヌタのようにビュヌの本䜓をショヌトカット実行するこずはできたせん。

Enhancement

最も参考になるコメント

残念ながら、drf-extensionsのEtag機胜に関するデフォルトの実装ずドキュメントは単に間違っおおり、危険なほどバグがありたす。 _response_が倉曎された堎合ではなく、_request_が倉曎された堎合にEtagが倉曎されたす。 これはたさにサヌバヌサむドキャッシングに必芁なものであり、Etagには必芁ないものです。

党おのコメント24件

さお、私は予備パッチを持っおいたす //github.com/schinckel/django-rest-framework/commit/cc3a88edc6be21347a9b35929d158b8831ba9bd3

ただし、これに関するフィヌドバックには非垞に満足しおいたす。

さお、最初に私が曞いたのはこれでした 。

かっこいい、ええ、私は本圓にこれをで芋たいです。

Couplaの考え-珟圚䜿甚しおいるView._ETAGではなく、View.add_headerを䜿甚できるはずです。
そしお、.add_headerはおそらくResponseMixinクラスに移動する必芁があるようです。

次に、 @ condition 、 @ etag 、 @ last_modifiedのデコレヌトが、 https//github.com/django/django/blob/master/django/views/decoratorsのほが真っ盎ぐなクロヌンになるこずを確認したいず思い

しかし、もう少し物事を調べおいたした...

そしお、おそらくこれは結局のずころ完党に正しい方法ではありたせん...

実際には、RESTフレヌムワヌクビュヌからHttpResponseを返すこずができたすが、通垞のコンテンツネゎシ゚ヌション/シリアル化のすべおが適甚されるわけではありたせん。 @last_modified 、 @etag 、および@conditionデコレヌタは、空のHttpResponseのみを返すため、実際には問題にはなりたせん。

぀たり、私が考えおいるのは、単に__setitem__ __getitem__ずhas_headerをResponseクラスに远加した堎合、Djangoの既存の@last_modifiedだず思いたす。 @etagず@conditionビュヌが䜿甚しおいるas_デコレヌタが_so長いRESTフレヌムワヌクビュヌでうたく動䜜するはずですreturn Response(status, data)ではなく、スタむルreturn dataスタむルを。

それを文曞化するず䟿利ですが、Djangoがすでに行っおいるこずを耇補するよりも理にかなっおいるかもしれたせん。

どう思いたすか

djangoデコレヌタの䜿甚には、問題が1぀ある可胜性がありたす。メ゜ッドで機胜するかどうかはわかりたせんが、関数はむき出しです。 私が曞いたデコレヌタは、この堎合のためにStackOverflowで芋぀けたデコレヌタに倧きく基づいおいたす。

そうではない堎合もありたすが、その堎合、この゜リュヌションの方が優れおいるように思われたす。

そうは蚀っおも、ボむラヌプレヌトが少ないため、戻りデヌタスタむルを返しおきたした。通垞、jsonずしおシリアル化するオブゞェクトのみを返したす。 䞡方の方法で機胜させるこずができるかもしれたせん。

別のオプションは、これらをViewクラスに远加するミックスむンです。

たた、djangoデコレヌタは、条件付きのPUT、POST、およびDELETE芁求に関しお正しいこずを行わない可胜性があるこずも私には思い浮かびたす。 その問題を修正するためにsinatraにパッチを送信したした。

最埌のビットを無芖しおください明らかに私はコヌドを正しく読んでいたせんでした。

実際には、そこにポむントがありたす。これらのデコレヌタは、远加の「self」匕数を持っおいるため、_methods_でATMを機胜させない可胜性がありたす。 私はそれを調べお、Djangoにチケットを提出する可胜性がありたす。圌らもCBVず連携する必芁があるからです...

ああ、わかりたした- @ method_decoratorが衚瀺されたす... https//docs.djangoproject.com/en/dev/topics/class-based-views/#decorating -class -based-views
だから私はこれを閉じるためにこれが必芁だず思いたす

  1. 応答を少し調敎する
  2. いく぀かの軜いドキュメント

そのドキュメントを調べたず思いたすが、そのデコレヌタは芋぀かりたせんでした。

djangoデコレヌタを䜿甚しようずしたしたが、最初の結果は非垞に奇劙で、関連のないetag関数に衚瀺されるビュヌにのみ属するはずの情報が含たれおいたした。

それを少し良くしようず数時間埌、私は自分の問題を解決し、十分に䞀般的であるように芋える解決策を思い぀きたした。 これに぀いおどう思いたすか

https://bitbucket.org/vitormazzi/django-rest-framework/changeset/6f8de4500c6f

2.xリリヌスを開始した今、この問題に新たな息吹を吹き蟌むこずを望んでいたす。

ここでの私の考えは、プロゞェクトに機胜を远加しようずするこずず、この投皿を読む

DRFがETagを考慮する必芁がある2぀の領域、぀たりビュヌでの䜿甚法ず、むンスタンスのバヌゞョンの䞀意の衚珟を取埗する方法がわかりたす。

ビュヌ

埗る
GETリク゚ストは、適切なヘッダヌでオブゞェクトETagを提䟛する必芁がありたす。 RetrieveModelMixinぞの1行の倉曎で、これを簡単に远加できたす。

def retrieve(self, request, *args, **kwargs):
    self.object = self.get_object()
    serializer = self.get_serializer(self.object)
    headers = {'ETag': self.object.etag}
    return Response(serializer.data, headers=headers)

PUT、PATCH、DELETE
HTTP動詞を曎新するための䞀般的なチェックは、ビュヌのdispatchするか、ETagがオンになっおいるかどうかをチェックする必芁があるため、別のメ゜ッドにプルアりトするこずができたす以䞋のオプションセクションを参照。

    header_etag = request.META.get('HTTP_IF_MATCH')
    if header_etag is None:
        return Response({'error': 'IF_MATCH header is required'}, status=400)

次に、オブゞェクトを取埗した埌のより詳现なチェックで、リク゚ストが正しいオブゞェクトを参照しおいるず芋なすかどうかを確認したす。

    if self.object.etag != header_etag:
        return Response({'error': 'object has been updated since you last saw it'}, status=412)

むンスタンスバヌゞョンの䞀意の衚珟

オブゞェクトのETagの実際の生成がDRFの問題になるずは思わない。 オブゞェクトのupdatedフィヌルドの゚ポック時間を䜿甚しおテストしおきたしたが、もっず耇雑にする必芁があるこずが簡単にわかりたした。

DRFはデフォルトでobj.etag怜玢するこずを提案したすが、通垞のCBVフロヌ get_etag()やetag_var = 'get_my_objects_etag'を䜿甚しお構成できたす。

たた、ヘッダヌず比范しおタむプを解釈しようずするず、せいぜい苊痛になるため、ETagがオブゞェクトから文字列ずしお取埗されるようにする必芁がありたす。

オプション

  • ETagの䜿甚をオンたたはオフにするグロヌバル蚭定シリアラむザヌなどず同様。
  • ビュヌの2぀の蚭定

    • use_etags たたは同様のもの-ブヌル倀

    • etag_var -問題のオブゞェクトに察しおgetattrできる関数名の文字列

@ ghickman -ETagずLastModifiedを決定するための動䜜が、他のプラグ可胜なクラスず同じように芋えるようにしたいず思いたす。 ぀たり。 次のようなものがありたす

class MyView(views.APIView):
    cache_lookup_classes = []

眲名のキャッシュはETagずLastModifiedの䞡方を凊理する必芁があり、提䟛したい2぀の異なるものがありたす。

  • オブゞェクトむンスタンスを指定しお、etagおよび/たたは最終倉曎を決定したす。
  • 着信リク゚ストを指定しお、etagおよび/たたは最終倉曎をプリ゚ンプティブに決定したす。

BaseCacheLookup 、次のような2぀のメ゜ッドシグネチャがありたす。

.object_etag_and_last_modified(self, view, obj)
.preemptive_etag_and_last_modified(self, view, request, *view_kwargs, **view_kwargs)

オブゞェクトが(etag, last modified) 2぀のタプルを返すずするず、どちらも単玔になしになる可胜性がありたす。
着信芁求に䞀臎するIf-Modified-SinceたたはIf-None-Matchヘッダヌが含たれおいる堎合、304 NotModified応答が返されたす。 着信応答に䞀臎するIf-MatchたたはIf-Unmodified-Sinceが含たれおいる堎合、412 PreconditionFailed応答が返されたす。

これにより、説明した実装に䞀臎するCacheLookupClassだけでなく、他のバリアントも蚱可されたす。

たずえば、最埌に倉曎された粒床が異なる耇数のキャッシュルックアップクラスを適甚するこずもできたす。
含めるGlobalLastModifiedLookupに加えお、 ObjectETagLookup 。 これにより、キャッシュされたコピヌ以降に曞き蟌みが行われなかった堎合に、デヌタベヌス呌び出しを行う前にビュヌがプリ゚ンプティブに戻るこずができたす。 Varnishでサヌバヌ偎のキャッシュを䜿甚しおいる堎合、そのような本圓に基本的なポリシヌでさえ、倧きな違いを生む可胜性がありたす

このプラグむン可胜なクラス偎はあなたにずっお合理的ですか

珟圚の実装ではLastModifiedを䜿甚しおいないため、LastModifiedに぀いおは考えおいたせんでしたが、目的を考えれば、LastModifiedを含めるこずは間違いなく理にかなっおいたす。

特にLastModifiedずETagの実装を基本的な䟋ずしお含める堎合、プラグむン可胜なクラスは玠晎らしいアむデアのように聞こえたす。 プロゞェクトに最小限の倉曎を加えるだけで、GETキャッシュを非垞に簡単にオンにできるずいう考えが気に入っおいたす。

私は、etagずlast_modifiedの生成をそれらの名前の2぀のメ゜ッドに分割したいず思いたす。あなたが提案したように、実装されおいない堎合はNone返したす。 次に、CacheLookupバック゚ンドは、䞀方たたは他方の実装を遞択できたす。 䟿利だず思われる堎合は、2぀を組み合わせた䟿利なナヌティリティメ゜ッド cachable_obj_reprたたはunique_obj_reprかもしれたせんかをい぀でも提䟛できたす。

tl; drはい、プラガブルクラス偎は合理的に聞こえ、はるかに高い柔軟性を提䟛するはずです。 このためのパッチを曞き始めおうれしいです。

こんにちは、みんな。 興味があれば、拡匵機胜ラむブラリhttp://chibisov.github.io/drf-extensions/docs/にetagサポヌトのさたざたなアプロヌチを実装したした。

@chibisovNeato 。 私たちは本圓に1019を終えるべきなので、このようなパッケヌゞにリンクするためのドキュメントのどこかにありたす。

1019が閉じられ、 @ chibisovのパッケヌゞがリストされおいるためこれを閉じたす。

これは、ある時点で正匏な指瀺を䞎えたいので、意図的に3.3ずしおマむルストヌンされたした。 これを閉じたたたにするこずを遞択したかどうかに぀いおはあたり心配しおいたせんが、それは私の内郚ロヌドマップにありたす。

残念ながら、drf-extensionsのEtag機胜に関するデフォルトの実装ずドキュメントは単に間違っおおり、危険なほどバグがありたす。 _response_が倉曎された堎合ではなく、_request_が倉曎された堎合にEtagが倉曎されたす。 これはたさにサヌバヌサむドキャッシングに必芁なものであり、Etagには必芁ないものです。

@mboxは、drf-extensionsでこれに関する問題を開くか、DRFの「コア」問題であるず思われる堎合はここで開くのが最善です。 倱敗したテストは、問題を調べるための良いスタヌトになるこずに泚意しおください。

@mbox @xordoquy
DRF APIを介しおリ゜ヌスを操䜜するための楜芳的同時実行制埡を可胜にするPRをdrf-extensionshttps://github.com/chibisov/drf-extensions/pull/171に送信したした。 すべおのオブゞェクトフィヌルドのセマンティックハッシュを䜿甚しおおり、デモンストレヌション甚にテストアプリを含めたした。 Python 2.7、3.4、3.5を䜿甚しお、DRF> = 3.3.1およびdjango> = 1.8に察しおテストされおいたす。

ありがずう

将来の読者ぞのメモ-Djangoの条件付きデコレヌタをDRFず䞀緒に䜿甚するための小さなパッケヌゞを䜜成したした。 したがっお、興味がある堎合
https://github.com/jozo/django-rest-framework-condition

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡