1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Django】Typeエラー「Object of type 'bytes' is not JSON serializable」の原因と解決方法

Posted at

エラー概要

DjangoでTypeError Object of type 'bytes' is not JSON serializableが表示されました。本記事ではそのエラー対応について記載します。
image.png

前提

以下のコードがあるとします。

def filter_company_rank(request):
    query_set = CompanyRank.objects.all()

    # フリーキーワードで検索する
        # 省略

    return get_list_data_table(query_set)

def get_list_data_table(query_set):
    
    data = query_set.select_related(
        'company_rank_id'
    ).values(
        'company_rank',
        'update_date',
        'update_user_id__username',
    )
    return JsonResponse(json.dumps(data))

def get_all_data(request):
    result = filter_company_rank(request)
    return result

上記のコードでは、フリーキーワードでユーザーが入力したキーワードがDBにあるかどうか検索して表示する関数を書いています。
ここで、return JsonResponse(json.dumps(data))のままだと上述のエラーが発生しました。

原因

原因は、QuerySetオブジェクトがデフォルトのJSONシリアライザによって直接シリアライズできなかったためです。
QuerySetとは、データベースからのクエリ結果を表すための特殊なオブジェクトで、以下のようなオブジェクトを指します。

<QuerySet [<CompanyRank: CompanyRank object (1)>]>

JSONシリアライザは通常、プリミティブなデータ型(整数、文字列、リストなど)や辞書形式のオブジェクトに対しては動作しますが、QuerySetオブジェクトはそのままではシリアライズできません。詳細は公式ドキュメントを参照ください。
json --- JSON エンコーダおよびデコーダ

また、json.dumps()を使用した場合、dataオブジェクトをJSON形式の文字列に変換することはできますが、そのままではシリアライズされたオブジェクトとして扱われません(ここがポイント)。

シリアライズとは

データを直列化してバイト列やテキストなどの形式に変換すること。
Pythonのjsonモジュールを使用してオブジェクトをJSON形式にシリアライズする場合、シリアライズ可能なオブジェクトはJSONに変換できます。ただし、シリアライズ不可能なオブジェクトはエラーが発生します。

反対に、JSON形式のデータをPythonのオブジェクトや文字列に変換することをデシリアライズと言います。

解決策

QuerySetオブジェクトをリストに変換してからJSONレスポンスに渡すことで、シリアライズ可能なデータとして扱うことができます。

return JsonResponse(json.dumps(data))

return JsonResponse(list(data), safe=False)

にすると正常にレスポンスが返ってきます。

ちなみに、以下でも成功しました。

return HttpResponse(json.dumps(list(data)), content_type='application/json')

ただし、json.dumps()の結果を文字列として直接返しています。また、JsonResponseは Django のビルトインのレスポンスクラスであり、自動的に正しいContent-Typeヘッダーを設定してくれますし、簡潔に記載できるので、JsonResponseの使用の方が推奨されると思います。

備忘録

non-dict objects to be serializedが出た場合

以下の場合In order to allow non-dict objects to be serialized set the safe parameter to False.というエラーが発生します。

return JsonResponse(json.dumps(list(data)))

これは、JsonResponseがデフォルトでは辞書型のオブジェクトを受け取り、それをJSON形式にシリアライズしてレスポンスとして返すためです。safeパラメータをFalseに設定することで、辞書以外のオブジェクトもシリアライズすることができるようになります。これにより、リストやクエリセットなどの辞書以外のオブジェクトも正常にシリアライズされます。

文字列をシリアライズできない他の例

以下は文字列をシリアライズできない例です。
冒頭と同じエラーがでます。

 return JsonResponse(json.dumps(data), content_type='application/json')
 return HttpResponse(json.dumps(data), content_type='application/json')
 return HttpResponse(json.dumps(data))
1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?