web-dev-qa-db-ja.com

django)のjsonフィールドで検索値を取得するクエリを作成する方法

データベースに次のようなjsonフィールドがあります

jsonfield = {'username':'chingo','reputation':'5'}

ユーザー名が存在するかどうかを確認できるようにクエリを作成するにはどうすればよいですか。何かのようなもの

username = 'chingo'
query = User.objects.get(jsonfield['username']=username)

上記のクエリが間違っていることは知っていますが、それにアクセスする方法があるかどうか知りたいですか?

18
shanks

この使用法はややアンチパターンです。また、その実装は通常のパフォーマンスを発揮せず、おそらくはエラーが発生しやすくなります。
通常、フィールドを検索する必要がある場合は、jsonfieldを使用しないでください。 Danielが指摘したように、RDBMSが提供する方法またはMongoDB(より高速なBSONで内部的に動作する)を使用します。

JSON形式の決定論 のため、containsを使用してそれを達成できます(regexは複数の'\'を処理するときに問題があり、さらに遅い)、使用するのは良いことではないと思いますusernameこのように、代わりにnameを使用します。

def make_cond(name, value):
    from Django.utils import simplejson 
    cond = simplejson.dumps({name:value})[1:-1] # remove '{' and '}'
    return ' ' + cond # avoid '\"'

User.objects.get(jsonfield__contains=make_cond(name, value))

それは

  • 同じダンプユーティリティを使用するjsonfield(ここではsimplejson
  • nameおよびvalueではありませんあまりにも特別(これまでのところegde-caseはわかりません、誰かが指摘するかもしれません)
  • jsonfieldデータが破損していない(可能性は低いですが)

実際、私は編集可能なjsonfieldに取り組んでおり、そのような操作をサポートするかどうかを考えています。否定的な証拠は上で述べたように、それはまあ、いくつかの黒魔術のように感じます。

12
okm

Django-jsonfieldパッケージを使用している場合、これは簡単です。次のようなモデルがあるとします。

from jsonfield import JSONField
class User(models.Model):
    jsonfield = JSONField()

次に、特定のsernameのレコードを検索するには、次のようにします。

User.objects.get(jsonfield__contains={'username':username})
20
bwv549

Django 1.9以降、PostgreSQLのネイティブJSONFieldを使用できるようになりました。これにより、JSONの検索が非常に簡単になります。この例では、次のクエリが機能します。

User.objects.get(jsonfield__username='chingo')

古いバージョンのDjangoを使用している場合、またはMySQLなどとの互換性のためにDjango JSONFieldライブラリを使用している場合でも、クエリを実行できます。

後者の状況では、jsonfieldはテキストフィールドとして保存され、Djangoに取り込まれるとdictにマップされます。データベースでは、データは次のように保存されます

{"username":"chingo","reputation":"5"}

したがって、テキストを簡単に検索できます。このsiutationでのクエリは次のようになります。

User.objects.get(jsonfield__contains='"username":"chingo"')
12
freethebees

PostgreSQLを使用している場合は、rawsqlを使用して問題を解決できます。

username = 'chingo'
SQL_QUERY = "SELECT true FROM you_table WHERE jsonfield::json->>'username' = '%s'"
User.objects.extra(where=[SQL_EXCLUDE % username]).get()

どこ you_tableはデータベース内のテーブルの名前です。

プレーンテキストのようにJSONを操作する場合のメソッドは、非常に悪い方法のように見えます。ですから、データベースのより良いスキーマが必要だと思います。

1
Shmele

これがあなたの問題を解決することを私が見つけた方法です:

search_filter = '"username":{0}'.format(username)
query = User.objects.get(jsonfield__contains=search_filter)

お役に立てれば。

1
Hayk Davtyan

2019:@freethebeesが指摘しているように、今では次のように簡単です:

User.objects.get(jsonfield__username='chingo')

ただし、ドキュメントの例で説明されているように、深くクエリを実行できます。jsonが配列の場合は、整数を使用してインデックスを作成できます。

https://docs.djangoproject.com/en/2.2/ref/contrib/postgres/fields/#querying-jsonfield

>>> Dog.objects.create(name='Rufus', data={
...     'breed': 'labrador',
...     'owner': {
...         'name': 'Bob',
...         'other_pets': [{
...             'name': 'Fishy',
...         }],
...     },
... })
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': None})

>>> Dog.objects.filter(data__breed='collie')
<QuerySet [<Dog: Meg>]>

>>> Dog.objects.filter(data__owner__name='Bob')
<QuerySet [<Dog: Rufus>]>

>>> Dog.objects.filter(data__owner__other_pets__0__name='Fishy')
<QuerySet [<Dog: Rufus>]>

これはpostgres用ですが、MySQLのような他のDBでも同じように機能すると思います

1
Charles Thayer

あなたはそれをすることはできません。 JSON BLOBではなく、構造化データに通常のデータベースフィールドを使用します。

JSONデータを検索する必要がある場合は、MongoDBなどのnoSQLデータベースの使用を検討してください。

0
Daniel Roseman