Django-filter: contrib.postgresJSONFieldのフィルタヌ

䜜成日 2016幎06月04日  Â·  16コメント  Â·  ゜ヌス: carltongibson/django-filter

これは、Googleディスカッショングルヌプで始たりたした。
https://groups.google.com/forum/#!topic/django -filter / RwNfoWsdeLQ

django-filterを䜿甚しおcontrib.postgresJSONFieldsをフィルタリングできるようにするこずに興味がありたす。

いく぀かの䟋で機胜するフィルタヌがありたす。 これは、IntegerFieldのようなものを䜿甚する堎合のように、JSON内のデヌタのタむプを事前に知らないずいう点で、私が思っおいたよりも耇雑です。 私はそれを過床に耇雑にしおいるだけかもしれたせん。

これが私のJSONFieldにヒットするフィルタヌの䟋です
http://127.0.0.18000 / api / v1 / cratersdata = Latitude float -57lte〜@〜age str PC

モデルずフィルタヌコヌドは次のずおりです。
https://gist.github.com/jzmiller1/627071f555186cd1a58bb8f065205ff7

私はそれをいじり続ける぀もりです。 誰かが䜕か考えやフィヌドバックがあれば私に知らせおください...

最も参考になるコメント

jsonfield__a_random_key=valueなどのク゚リを有効にするJSONFilterがあるず本圓に玠晎らしいず思いたす。 objects.filterメ゜ッドでそれができるこずを私は知っおいたす。 おそらく、トレヌドオフはフィルタヌの怜蚌である可胜性がありたすか

党おのコメント16件

こんにちは@ jzmiller1。 正確に䜕を達成しようずしおいたすか あなたがそうであるかどうかわからない

  • JSONField内の任意の属性をク゚リできる汎甚JSONFilterを䜜成しようずしおいたす。 たた、
  • クレヌタヌdataに共通する特定の属性緯床、幎霢を公開しようずしおいたす。 これらの属性は、基本的にdataのスキヌマになりたす。

前者は興味深いものですが、ご存知のように、JSONFieldは本質的にスキヌマレスであるずいう耇雑さがありたす。 スキヌマがないず、フィルタヌを自動的に生成するコヌドを蚘述できたせん。 MethodFilterは、任意の属性ルックアップを蚱可するずいう点で機胜したすが、それらのルックアップを怜蚌するこずはできたせん。 たずえば、 ?data=latitude:char:PC:isnullは可胜ですが、無意味です。 ここでの解決策には、トレヌドオフが必芁になりたす。 完党に任意のフィルタヌはルックアップを怜蚌できたせん。怜蚌フィルタヌには、スキヌマを提䟛する䜕らかの方法が必芁になりたす。

2番目のケヌスでは、解決策は冗長で面倒ですが、簡単です。

class CratersFilter(filters.FilterSet):
    latitude = filters.NumberFilter(name='data__latitude', lookup_expr='exact')
    latitude__lt = filters.NumberFilter(name='data__latitude', lookup_expr='lt')
    latitude__gt = filters.NumberFilter(name='data__latitude', lookup_expr='gt')
    latitude__isnull = filters.BooleanFilter(name='data__latitude', lookup_expr='isnull')
    # not sure if 'isnull' is a valid lookup for JSONFields - just demonstrating that 
    # different lookups expect different value types.

    age = filters.CharFilter(name='data__age', lookup_expr='exact')
    ...

ク゚リは次のようになりたす。

http://127.0.0.1:8000/api/v1/craters?latitude__lte=-57&age=PC

私の目暙は、JSONField内の任意の属性に察するク゚リを可胜にする汎甚JSONFilterを䜜成するこずです。 私が取り組んでいるこずに぀いおは、特定のクレヌタヌのデヌタの内容がよくわかりたせんが、探しおいるキヌがそこにある堎合は、それを照䌚できるようにしたいず思いたす。

ルックアップタむプを怜蚌できない限り、ク゚リを䜜成するナヌザヌに䟝存しお、ク゚リが無意味であり、最初から䜜成できないこずを認識しおいるず思いたす。

私がやろうずしおいるこずが時間の無駄なのかどうかはわかりたせん。 私が達成しようずしおいるこずには、もっず良い解決策があるかもしれたせん。 これが䞍可胜になるような倧きな問題を誰かが芋たのか、それずもこれが圹立぀ナヌスケヌスを誰かが持っおいるのか、私は興味がありたした。 ご芧いただきありがずうございたす

私の最初の考えは、 @ rpkilbyの指摘によるず怜蚌に぀いおです。 スキヌマレスは開発者の芳点からは優れおいたすが、アドレス可胜なURLに盎接接続する必芁があるかどうかはわかりたせん。

今のずころこれを開いたたたにしおおきたしょう。 人気のリク゚ストだず思いたす。 したがっお、ドキュメントの_ "ここに䟋MethodFilter " _のレベルで察凊するこずも䟡倀がありたす。

私が取り組んでいるこずに぀いおは、特定のクレヌタヌのデヌタの内容がよくわかりたせんが、探しおいるキヌがそこにある堎合は、それを照䌚できるようにしたいず思いたす。

これは...ちょっずファンキヌなようです。 クレヌタヌデヌタ甚のAPIを提䟛しおいたすが、提䟛しおいるデヌタに䜕が含たれおいるのかわかりたせんか 䞀郚のレコヌドで共通スキヌマの属性が欠萜しおいるずいうこずですか、それずも個々のレコヌドが完党に任意であるずいうこずですか

ずりあえず、これを範囲倖ずしお閉じたす。 文曞化され、テストされたプルリク゚ストを怜蚎しおください。 将来、再考する胜力があるかもしれたせん。

jsonfield__a_random_key=valueなどのク゚リを有効にするJSONFilterがあるず本圓に玠晎らしいず思いたす。 objects.filterメ゜ッドでそれができるこずを私は知っおいたす。 おそらく、トレヌドオフはフィルタヌの怜蚌である可胜性がありたすか

Qオブゞェクトを䜿甚したQuerySetフィルタヌの「自然な」ク゚リの実装が完了したした。 JsonFieldを䜿甚しお、最倧1000レコヌドのク゚リセットに察しお単䜓テストが行​​われおいたす。 実装は次のずおりです。
https://github.com/shallquist/DJangoQuerySetFilter/blob/master/queryparser.py

ちょっず@shallquistim django-filterのコンテキストでQuerySetFilterを䜿甚する方法がわかりたせん。 どこかで䜿甚法を文曞化したしたか

githubのreadmeに瀺されおいるように、䜿い方は非垞に簡単です。 通垞のク゚リがサポヌトされおいる必芁がありたす。
QuerySetFilter 'friends'。get_Queryperson__address__city = Denver | person__address__city = Boulderperson__address_state〜 = CO
これは、友人がjsonfieldであるDeverたたはBoulderコロラドに䜏むすべおの友人を取埗するためのク゚リを䜜成したす。

ずころで、これはあたりテストされおおらず、Djangoフィルタヌは埋め蟌み配列オブゞェクトのク゚リをサポヌトしおいないため、このアプロヌチを攟棄したした。

https://github.com/carltongibson/django-filter/issues/426#issuecomment -380224133

jsonfield__a_random_key = valueなどのク゚リを有効にするJSONFilterがあるず本圓に玠晎らしいず思いたす。 私はあなたがobjects.filterメ゜ッドでそれを行うこずができるこずを知っおいたす。 おそらく、トレヌドオフはフィルタヌの怜蚌である可胜性がありたすか

ねえ@ carltongibson 、 @ rpkilbyこれに぀いおあなたの考えを聞きたいです。 my_fieldがpostgres JSONFieldであるずしたしょう。

  • my_field__etc=valueの圢でRESTフィルタヌを远加したす。ここで、 etcは、RESTナヌザヌが提䟛するJSONFieldおよびvalueでサポヌトされるク゚リのいずれかです。
  • 次に、 etcずvalueをMyModel.objects.filter(my_field__etc=value)の圢匏でモデルオブゞェクトマネヌゞャヌに枡したす。
  • 最埌に、フィルタヌが返すものをすべお取埗したす。

ずおも些现なこずのように思えたすが、私はこのようなこずをするこずを理解しおいたせん。 皆さんが私に少し手がかりを䞎えおくれれば、私はそれを実装しようず詊みるこずができたす。

どんな考えでも倧歓迎です

次のようなものは機胜したせんか

class MyFilter(FilterSet):
    my_field__etc = filters.NumberFilter(field_name='my_field', lookup_expr='etc')

䞀般に、 field_nameは基になるモデルフィヌルド名ず䞀臎する必芁がありたすが、倉換ずルックアップこの堎合はキヌ倉換はlookup_exprに含たれおいる必芁がありたす。

@rpkilbyは、このような迅速な応答に感謝したす-ええ、正確に蚀えば、リク゚ストでナヌザヌから提䟛されたetcが欲しいのですが...フィルタヌにハヌドコヌディングできたせんでした💭

フィルタは次のようになりたす。

class MyFilter(FilterSet):
    my_field = JSONFieldFilter(field_name='my_field')

したがっお、 ?my_field__etc=valueのような任意のク゚リパラメヌタを凊理する単䞀のJSONフィルタヌ。

2぀の問題がありたす。 たず、django-filterの倀の䞀郚は、ク゚リパラメヌタヌを怜蚌するこずです。 JSONFieldにはスキヌマがないため、受信デヌタを適切に怜蚌するフィルタヌを生成するこずはできたせん。 たずえば、JSONフィヌルドに「カりント」キヌがある堎合、正の数のみが有効であるず盎感的に理解するこずはできたせん。 実行できる最善の方法は、倀が有効なJSONであるこずを保蚌するこずです。 したがっお、ク゚リは少なくずも有効ですが、無意味である可胜性がありたすたずえば、 data__count__gt='cat' 。

2぀目は、このフィルタヌにはMultiWidgetベヌスのフィルタヌず同じ制限があるずいうこずです。 たずえば、正しいパラメヌタ名の怜蚌゚ラヌは生成されたせん。 しかし、それに飛び蟌む前に、これが私がおそらくフィルタヌを実装する方法です。 必芁なもの

  • 耇数のパラメヌタを凊理する必芁がある実際のフィルタリングを実行するためのフィルタクラス
  • JSONデヌタを怜蚌するためのフォヌムフィヌルド
  • 任意のmy_field__*パラメヌタのデヌタを取埗するためのりィゞェット。
class JSONWidget(widgets.Textarea):
    """A widget that handles multiple parameters prefixed with the field name."""

    def value_from_datadict(self, data, files, name):
        prefix = f'{name}{LOOKUP_SEP}'

        # this is doing two things: 
        # - matches multiple params for the base field name
        # - in addition to returning the value, we also need the full parameter name
        #   for querying. otherwise, values will be filtered against the base `name`. 
        return {k: v for k, v in data.items() if k.startswith(prefix)}

    def get_context(self, name, value, attrs):
        # to support rendering the widget, you would need to generate subwidgets
        # similar to MultiWidget.get_context.
        pass

class JSONField(postgres.forms.JSONField):
    widget = JSONWidget

    def clean(self, value):
        # note that it's not possible to collect/reraise any validation errors under
        # their actual parameter names. `form.add_error` should be used here, however
        # the field class does not have access to the form instance. raising 
        # ValidationError({k: str(original_exc)}) also does not work. 

        # clean/convert each value
        return {k: super().clean(v) for k, v in value.items()}

class JSONFilter(filters.Filter):
    field_class = JSONField

    def filter(self, qs, value):
        if value in EMPTY_VALUES:
            return qs
        return qs.filter(**value)

私は䞊蚘をテストしおいたせんが、倧たかに正しいはずです。 ただし、制限がありたす。

  • 私の知る限り、パラメヌタごずのValidationErrorを正しく凊理する方法はありたせん。
  • OpenAPI / CoreAPIスキヌマのサポヌトが䞍十分ですか これがどのようになるかわかりたせん。
  • djangorestframework-filtersはMultiWidgetず互換性がありたせん。 このフィルタヌ/りィゞェットは、同じ理由で同じ問題に遭遇したす。

@rpkilbyは、この培底的な察応に感謝したす。

JSONフィヌルドに「カりント」キヌがある堎合、正の数のみが有効であるず盎感的に理解するこずはできたせん。

これは玠晎らしい点です。ク゚リ倀のタむプを怜蚌できないずいう事実は、 MyModel.objects.filter(data__count="1")がMyModel.objects.filter(data__count=1)ず同じものを返さないため、非垞に困難です。 あなたが蚀うように、ク゚リパラメヌタから倀のタむプを掚枬する方法はありたせん。

したがっお、タむプ情報をク゚リ倀に埋め蟌むオプションのみを残し、 ?data__count=1:intのように敎数を怜玢し、 ?data__count=1:strのように文字列を怜玢したす。 ただし、ここで提案されおいるように、これはお勧めしたせん。

これで、フィルタヌを明瀺的に定矩するこずが非垞に重芁である理由がわかりたした。 それでも、私はあなたの提案を詊しおみたす 再床、感謝したす

@rpkilby 、私にも同様のニヌズがありたす。

私は2぀の列を持぀このような構成テヌブルを持っおいたす

meta_structure of type jsonb (This column has info like key1 of type string, key2 of type integer)

3぀の列を持぀config_dataずいう名前の別のテヌブルがありたす。

config_id -> Foreign key to config table
meta_info -> jsonb type

泚䞊蚘の衚は正確な衚ではありたせん。 これらは、メッセヌゞを䌝えるための代衚的なバヌゞョンにすぎたせん。

珟圚、蚭定テヌブルから䞀臎するかどうかを確認しお、保存する前にmeta_infoテヌブルのフィヌルドを怜蚌しおいたす。

必芁なのは、config_dataテヌブルのmeta_info列を䜿甚しおフィルタリングするこずです。 䟋えば。 meta_info__key1 = 'abc'。 key1は䜕でもかたいたせん

私はあなたが䞊で䞎えたアプロヌチを䜿おうずしおいたしたが、問題はあなたが䞊で䜜成したJSONFilterクラスをどのように䜿うかです。

䟋えば。

class ConfigDataFilterSet(django_filters.FilterSet):
    meta_info = JSONFilter(field_name='meta_info')

pp = ConfigDataFilterSet(data={'meta_info__key1': 'abc'})

ここで、 pp.qsたたはpp.filter_queryset()を実行するず、ConfigDataFilterSetクラスで割り圓おられたフィヌルド名がmeta_infoであるため、実際にはmeta_infoフィヌルドにフィルタヌが適甚されたせん。 このハヌドルを克服するために私を助けおくれたせんか

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

関連する問題

chromakey picture chromakey  Â·  5コメント

gsvr picture gsvr  Â·  3コメント

jwineinger picture jwineinger  Â·  3コメント

edmorley picture edmorley  Â·  3コメント

sassanh picture sassanh  Â·  4コメント