2016-11-29 3 views
0

JSONFieldフィールドからサブキーを抽出し、Querysetの値に注釈を付けることは可能ですか?私は、Pythonコードの後処理ではなく、クエリ内の値を抽出しようとしています。クエリ中に `django.models.F`または同様のメソッドを使用してDjango JSONFieldのキーにアクセスするにはどうすればよいですか?

モデルのアーキテクチャは次のとおりです。

  • ジャンゴ1.10
  • モデルは、APIの応答を格納するためのdjango.contrib.postgres.fields.JSONField called data`を持っています。この例はTwitterです。
  • 他のフィールドはprofile_idscreen_nameです。残りのデータはdataフィールドに格納されているため、アドホックで照会することができます。

私はannotatedjango.models.Fを組み合わせることができるだろうと思ったが、私は次のエラーを取得しています:

> models.TwitterUser.objects.annotate(foll_count=F("data__followers_count")) 

Traceback (most recent call last): 
    File "<console>", line 1, in <module> 
    File "/Virtualenv/env_name/lib/python3.5/site-packages/django/db/models/manager.py", line 85, in manager_method 
    return getattr(self.get_queryset(), name)(*args, **kwargs) 
    File "/Virtualenv/env_name/lib/python3.5/site-packages/django/db/models/query.py", line 914, in annotate 
    clone.query.add_annotation(annotation, alias, is_summary=False) 
    File "/Virtualenv/env_name/lib/python3.5/site-packages/django/db/models/sql/query.py", line 971, in add_annotation 
    summarize=is_summary) 
    File "/Virtualenv/env_name/lib/python3.5/site-packages/django/db/models/expressions.py", line 463, in resolve_expression 
    return query.resolve_ref(self.name, allow_joins, reuse, summarize) 
    File "/Virtualenv/env_name/lib/python3.5/site-packages/django/db/models/sql/query.py", line 1462, in resolve_ref 
    self.get_initial_alias(), reuse) 
    File "/Virtualenv/env_name/lib/python3.5/site-packages/django/db/models/sql/query.py", line 1402, in setup_joins 
    names, opts, allow_many, fail_on_missing=True) 
    File "/Virtualenv/env_name/lib/python3.5/site-packages/django/db/models/sql/query.py", line 1370, in names_to_path 
    " not permitted." % (names[pos + 1], name)) 
django.core.exceptions.FieldError: Cannot resolve keyword 'followers_count' into field. Join on 'data' not permitted. 

私はそれをリバースエンジニアリングしようとしていますので、これを明示的にどこにも文書化されていませんDjangoの別の場所で使用されている二重のアンダースコアを使用します。私は、それがネイティブのPythonのdict(F("data")[followers_count"])のように別々にキーにアクセスしようとしましたが、それもうまくいきませんでした。

直接的な回答や他の分野への指針は認められます。

+0

同様の問題を抱えている誰かが見つかりました - http://hatethatcode.com/writing-queries-for-django-models-with-jsonfield.html - rawsqlが今のところORMはJSONFieldのアプローチに追いついています。 –

答えて

0

私は書面の時点でF()を使用できませんでしたので、フィールドにアクセスするためにRawSQLコールにフォールバックする必要がありました。

彼のブログにはHow to aggregate (min/max etc.) over Django JSONField data?José San Gilの前の作業に基づいています。

qs = models.TwitterUser.objects.annotate(followers=RawSQL(
     # The Postgres SQL query to access a JSON object field. 
     # `data` is the name of the JSONField in my schema. 
     # More: https://www.postgresql.org/docs/9.3/static/functions-json.html 
     "((data->%s))", 
     # The parameter to insert into the query and replace '%s' 
     # This could be a variable 
     # and the query adapted into a reusable universal function. 
     ("followers_count",) # In my example, this is the JSON sub-key I'm after 
     ) 
    ) 

注:私は括弧とうまくいけば、理解を助けるためにインデントしました。

annotateの前に.filter(data__has_key="insert_key_here")を追加して、問題のフィールドが含まれているアイテムのみを返すこともできます。これはORM内のJSONの素敵なネイティブメソッドであり、ORMを介して直接JSONサブフィールドにアクセスする同様の方法があることを願っています。