質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

6559閲覧

Djangoで日本語を含むcsvをimportしたい

naoyashiga

総合スコア8

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

1グッド

1クリップ

投稿2018/02/23 07:06

前提・実現したいこと

  • csvファイルをimportしてdbにinsertする
  • csvには日本語が入っている
  • web上にある管理ページのUIからボタンを押してcsvをuploadしてdbにinsert(Admin integrationしたい)

発生している問題・エラーメッセージ

「django-import-export」というライブラリを使っています。
https://github.com/django-import-export/django-import-export

管理画面ページ(admin)にあるUI経由でcsvをimportしようとすると以下のエラーが出ます。おそらく原因はuploadしようとしたcsvに日本語テキストが含まれていたからだと思います。

Imported file has a wrong encoding: 'ascii' codec can't decode byte 0xe3 in position 29: ordinal not in range(128)

・実装の参考にしたページ
How to Use django-import-export

試したこと

  • uploadしようとしたcsvの文字コードはutf-8
  • csvの内容が全て英語のときは問題なくuploadしdbにinsertできた
  • 管理ページからデータを編集し、そのデータに日本語入れても問題なく保存できた
  • django-import-exportの過去issueを読んだが直し方がわかりません

補足情報(FW/ツールのバージョンなど)

  • python 3.4.6
  • django 2.0.2
  • MySQL Ver 14.14 Distrib 5.7.21, for Linux (x86_64)
  • OS Ubuntu

直し方がわかる方がいらっしゃいましたらご回答していただけると幸いです。

退会済みユーザー👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

TL;DR

実行環境のロケールが、 "C" 等の UTF-8 でないロケールに設定されているからではないでしょうか。
もしロケールが原因なのであれば、 Ubuntu を御使いなら language-pack-ja 等のパッケージでロケールをインストールした上で LANG=ja_JP.UTF-8 ./manage.py runserver 等として UTF-8 のロケールを指定してサーバを起動すれば問題が解決できる可能性があります。

原因の考察

django-import-export パッケージのコード中、当該メッセージ "Imported file has a wrong encoding" を出力し得るのは以下の個所と見受けられます。

https://github.com/django-import-export/django-import-export/blob/7645954f241aa7f042e9ed7871482f352927097c/import_export/admin.py#L267-L273

try: data = tmp_storage.read(input_format.get_read_mode()) if not input_format.is_binary() and self.from_encoding: data = force_text(data, self.from_encoding) dataset = input_format.create_dataset(data) except UnicodeDecodeError as e: return HttpResponse(_(u"<h1>Imported file has a wrong encoding: %s</h1>" % e))

ここでは force_text() を使っていますので、そこで変換に失敗している可能性もありますが、指定されている self.from_encoding はデフォルトで UTF-8 のようなので、問題にはならずに済みそうです。

それよりももう一か所、怪しいのは直前の tmp_storage.read() の呼び出しの中身です。

https://github.com/django-import-export/django-import-export/blob/master/import_export/tmp_storages.py#L27-L43

class TempFolderStorage(BaseStorage): def open(self, mode='r'): if self.name: return open(self.get_full_path(), mode) else: tmp_file = tempfile.NamedTemporaryFile(delete=False) self.name = tmp_file.name return tmp_file def read(self, mode='r'): with self.open(mode=mode) as file: return file.read()

御覧の通り、 open() でファイルを開くときに、テキストモードで開いているのに encoding キーワード引数の指定がありません。この場合 Python 3 では、 実行環境のシステムで指定されたロケールに基づいてエンコーディングを推測し、自動的にデコードを行う 仕様となっています。恐らくここでロケールが適切でないため、 UTF-8 であると推測できずに ASCII で開こうとしてしまっているのではないでしょうか。

from_encoding という設定がありながらファイルを開く段階でロケールに依存して失敗するという話なので、 django-import-export のバグと言えそうです

解決方法

以上より、ロケール設定への依存が原因だと仮定した場合、解決方法は 3 通りくらいあるかと思います。

  1. ja_JP.UTF-8 等の UTF-8 ロケールをインストールし、システムのデフォルトに設定する
  2. django-import-export のコードを修正し、 open() 時に encoding キーワード引数を適切に指定する
  3. Python がシステムのロケールからエンコーディングを推測する locale.getpreferredencoding() 関数を hack する (検索してみてください)

1 が楽かとは思いますが、正攻法なのは 2 でしょうね。但し、今後のパッケージアップデートを考えると、修正した内容を pull request で送って merge してもらいたいという話もあり、コストは高いです。 3 はお勧めしません。

投稿2018/03/08 05:52

argparse

総合スコア1017

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

naoyashiga

2018/03/16 09:45

解決方法2で解決しました。丁寧な説明を提示してくださったので迷わず修正することができました。困っていたので本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問