前提・実現したいこと
実現したいこと:djangoにて、日本語で記入されたcsvをインポートできるようにしたい
使用言語:python3.6
フレームワーク:「Django1.11」
以下のサイトを参照に、djangoにてcsvアップローダーを作成しました。
【参照サイト】
https://torina.top/detail/324/
日本語にて記載されたcsvをインポートできるようにしたいのですが、
試しにcsvに「あいうえお」と入力しインポートした所、以下のエラーが発生してしまいました。
ValueError at /import/csv_import/
invalid literal for int() with base 10: 'あ'
こちらのバグを修正し、日本語のcsvをインポートできるようにするためには、
どこを修正したら良いでしょうか。
該当のソースコード
以下に、views.pyとmodels.pyのソースコードを記載いたします。
①views.py
___________________________
import csv
from io import TextIOWrapper, StringIO
from django.http import HttpResponse
from django.shortcuts import redirect
from django.views import generic
from .models import Post, Category
class IndexView(generic.ListView):
model = Post
def csv_import(request):
form_data = TextIOWrapper(
request.FILES['csv'].file, encoding='utf-8')
if form_data:
csv_file = csv.reader(form_data)
for line in csv_file:
post, _ = Post.objects.get_or_create(pk=line[0])
post.title = line[1]
post.text = line[2]
category, _ = Category.objects.get_or_create(name=line[3])
post.category = category
post.save()
return redirect('app:index')
def csv_export(request):
memory_file = StringIO()
writer = csv.writer(memory_file)
for post in Post.objects.all():
row = [post.pk, post.title, post.text, post.category.name]
writer.writerow(row)
response = HttpResponse(
memory_file.getvalue(), content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=db.csv'
return response
②models.py
from datetime import datetime
from django.db import models
class Category(models.Model):
name = models.CharField('カテゴリ名', max_length=255)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField('タイトル', max_length=255)
text = models.TextField('本文', max_length=255)
category = models.ForeignKey(Category, verbose_name='カテゴリ', null=True)
def __str__(self):
return self.title
③CSVファイルの内容
1 2 3 4
3 4 5 6
4 2 3 4
あ い う え
試したこと
①以下のサイトを参考に、views.pyを変更
【参考にしたサイト】
http://qiita.com/niwaringo/items/d2a30e04e08da8eaa643
【書き換え内容】
書き換えた関数:csv_import
旧:csv_importのrequest.FILES['csv'].file, encoding='utf-8')
新:request.FILES['csv'].file, encoding='shift-jis')
②以下のサイトを参考に、models.pyを変更
【参考にしたサイト】
http://docs.djangoproject.jp/en/latest/ref/unicode.html
http://www.metareal.org/2008/04/11/django-unicode-encode-error/
【書き換え内容】
書き換えたクラス:Category
旧: def str(self):
return self.name
新: def unicode(self):
return self.name
書き換えたクラス:Post
旧:def str(self):
return self.title
新:def unicode(self):
return self.title
上記のように、views.pyとmodels.pyを書き換え、再度確認してみましたが、
同様のエラーが発生する状態です。
int()の引数に対し書式が違うというエラーのようですが、
int関数を指定しておらず、どこを変更すればcsvファイルにて日本語を読み込めるのか、分からない状態です。
pythonもdjangoも初心者のため、不足している情報等ありましたら申し訳ございません。
どうぞ宜しくお願い致します。
【追記】
回答欄にてご指摘いただき、以下の修正を行いました。
①views.pyの関数の文字コードをutf_8_sigに指定
def csv_import(request):
form_data = TextIOWrapper(
#文字コードをutf_8_sigに指定
request.FILES['csv'].file, encoding='utf_8_sig')
if form_data:
csv_file = csv.reader(form_data)
for line in csv_file:
post, _ = Post.objects.get_or_create(pk=line[0])
post.title = line[1]
post.text = line[2]
category, _ = Category.objects.get_or_create(name=line[3])
post.category = category
post.save()
②models.py上の不要な変更点を元に戻す
※試したこと の項目の、②の変更点を変更前(冒頭に貼ったmodels.pyのコードの状態)に戻しました
再度ファイルをアップロードしてみた所、
以下のエラーが発生いたしました。
'utf-8' codec can't decode byte 0x82 in position 27: invalid start byte
csvファイル冒頭の「ID」の部分に日本語の入力をしているのがおかしいのかと考え、
「ID」は数字、ほかは日本語の状態にしアップロードしましたが、エラー内容は変わりませんでした。
1 2 3 4
3 4 5 6
4 2 3 4
5 あ い う
models.pyにてpyという変数を定義し、
views.pyのpost, _ = Post.objects.get_or_create(pk=line[0])の箇所を修正することで、
上記のエラーは解消できるでしょうか。
【追記②】
kacchan822様にご回答いただいたとおりにviewとmodelを修正し、
can110様にご指摘いただいたとおりにファイルの文字コードを「utf-8」へと変更した所、
無事にファイルをインポートすることができるようになりました!
コメント欄、回答欄にて適切なご指摘を下さり誠にありがとうございました。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
0
post, _ = Post.objects.get_or_create(pk=line[0])
→ おそらくこの部分ではないかと思います。
pkは、modelで特に指定していないようなので、int型です。エラーから見ると
lin[0]に入っているのはintではないのではないでしょうか。
(エラーメッセージ的には、「あ」?)
旧:csv_importのrequest.FILES['csv'].file, encoding='utf-8')
新:request.FILES['csv'].file, encoding='shift-jis')
→ 最近のExcelなどで作成されたcsvであれば文字コードは、utf8だと
思われますので、shift-jisでなくてよいと思います。
→ Excelで作られた場合は、BOM付きUTF8というのになっているので、
utf_8_sigを指定するとよいと思います。
旧: def str(self):
return self.name新: def unicode(self):
return self.name書き換えたクラス:Post
旧:def str(self):
return self.title新:def unicode(self):
return self.title
→ Python3.6を使用されているので、書き換えなくて問題ありません。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
質問への追記・修正、ベストアンサー選択の依頼
can110
2017/09/07 17:43
インポートしたCSVファイルも提示ください(先頭「ID」列にはどのような値が入っているか?)
komatsuna
2017/09/07 17:46 編集
質問をご確認いただきありがとうございます。
以下に、インポートしたCSVファイルの内容を記載いたします。 =======================================================
1 2 3 4
3 4 5 6
4 2 3 4
あ い う え =======================================================
最後の行の「あいうえ」の情報を入力した所、エラーが発生している状態です。
can110
2017/09/07 17:50
追記ありがとうございます。が、内容が確認しずらいため、CSVファイルをテキストエディタで開き全てコピーし、質問本文にコードで囲んで(貼付)追記ください。
komatsuna
2017/09/07 17:53
ご確認ありがとうございます。内容が確認しづらく、失礼いたしました。質問本文にcsvファイルの内容を追記いたしました。お手すきの際にご確認いただけますと幸いです。
can110
2017/09/07 18:00
修正ありがとうございます。先頭に「あ」が入っていますね。おおむねkacchan822さんの回答のとおりだと思います。
can110
2017/09/07 18:25
インポートしたCSVファイルの文字コードもテキストエディタなどで確認し追記ください(0x82なのでshift-jisだと思われますが)
komatsuna
2017/09/07 18:28 編集
ご指摘くださりありがとうございます!文字コードを確認した所、ANSIとなっておりました。utf-8を指定し再度アップしたところ、無事にファイルをアップロードすることができました。
文字コードに関しまして、とても初歩的な部分で躓いていたようです。
本件に関しまして、お時間を割いてくださりありがとうございました。