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

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

ただいまの
回答率

90.76%

  • Python 3.x

    5354questions

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

  • Django

    916questions

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

djangoにて日本語のcsvをインポートする方法

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 917

komatsuna

score 1

前提・実現したいこと

実現したいこと: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ページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • 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を指定し再度アップしたところ、無事にファイルをアップロードすることができました。 文字コードに関しまして、とても初歩的な部分で躓いていたようです。 本件に関しまして、お時間を割いてくださりありがとうございました。

    キャンセル

回答 1

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を使用されているので、書き換えなくて問題ありません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/07 18:01 編集

    ご回答くださりありがとうございます。
    models.pyに「pk」の指定をstr型で入れれば解決する、というようなことでしょうか。
    python3.6の場合は、strとunicodeの部分の書き換えは不要とのことでしたので、models.pyは変更前の状態に修正致しました。

    また、views.pyに関しましては、
    旧:request.FILES['csv'].file, encoding='shift-jis')
    新:request.FILES['csv'].file, encoding='utf_8_sig')

    というふうに記載を直し、再度日本語の含まれるファイルをアップロード致しました。
    そうすると、
    「'utf-8' codec can't decode byte 0x82 in position 27: invalid start byte」
    というエラーが発生している状態です。
    先程と同じく、日本語の部分で弾かれている状態かと考えておりますが、
    models.pyを修正することで解決できるでしょうか。

    キャンセル

  • 2017/09/07 18:49 編集

    上記修正の上、
    文字コードの修正を行ったところ無事にファイルをインポートできました。
    ファイルの文字コードを間違えて降りました。
    この度は、丁寧にご回答くださりありがとうございました。

    キャンセル

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

  • ただいまの回答率 90.76%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Python 3.x

    5354questions

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

  • Django

    916questions

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