61354


django, Python共に初心者です。

現在djangoで作ったWebサイト内で表示したタスクリストの書き出しをCSVで対応したいと考えております。  
CSVでの書き出しはいけるのですが、これをExcelで開くとutf-8のため、文字化けしてしまいます。  
下記のどこかに(推測では [writer =
csv.writer(response)]の部分あたりで文字コードを指定するのかと思っていますが、うまくいきませんでした。

また、それとは別に書き出したデータを見ていると、一部空欄のデータを認識せずエクセルで列ずれが発生しています。

<相談事項>  
1.Excelで書き出したCSVデータを開いたときに、文字化けせずに開けるようにする方法をご指導いただきたい  
2.DBが空欄だった場合も列を認識し、各項目をそろえて書き出しできる方法をご指導いただきたい

環境  
・OS : CentOS7  
・Python : 3.6.7  
・Django : 2.1  
・DB ： MariaDB

お手数ですがアドバイスいただけると幸いです。  
よろしくお願いいたします。

[code]

    from django.shortcuts import render, redirect, get_object_or_404
    from django.http import HttpResponseRedirect
    from django.http import HttpResponse
    from .forms import PostForm
    from .models import Task
    import csv
    
    def task_export(request):
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = 'attachment; filename = task_list.csv'
        writer = csv.writer(response)
        model = Task
        for task in Task.objects.all().order_by('id').reverse():
            writer.writerow([
                task.id,
                task.pic,
                task.issued_date,
                task.area,
                task.user,
                task.category1,
                task.category2,
                task.category3,
                task.task_content,
                task.details,
                task.duration,
                task.status,
                task.closed_date])
        return response
    
[/code]


CC BY-SA 4.0
2019-12-11T11:52:07.933
61344
2019-12-11T23:40:38.743
2019-12-11T12:12:36.230
34615
34615
question
python3 django csv array 文字化け
django / csvでのデータ書き出しの文字化け&列ずれ対策


> **1.Excelで書き出したCSVデータを開いたときに、文字化けせずに開けるようにする方法をご指導いただきたい**

に関しては、ファイルの先頭にUTF-8のBOMを書き込めば良いでしょう。  
[CSVファイルにUTF-8のBOMをつける -
Excelで開くと文字化けするUTF-8のCSVを文字コードを変換せずに開く方法](https://primarytext.jp/blog/1275#CSVUTF-8BOM)

>
> CSVファイルの文字コードはUTF-8のままで、BOMをつけるだけです。BOMをつけると、ExcelがUTF-8だと判断してくれてShift_JISじゃなくてUTF-8としてCSVを開いてくれます。

Djangoでどのようにすればよいかは、以下の記事が承認回答ありです。  
[Return a csv encoded in UTF-8 with BOM from
django](https://stackoverflow.com/q/30288666/9014308)

> Add the UTF-8 BOM to the response object before you write your data:
[code]

>     def render_to_csv(self, request, qs):
>       response = HttpResponse(content_type='text/csv')
>       response['Content-Disposition'] = 'attachment; filename="test.csv"'
>  
>       # BOM
>       response.write("\xEF\xBB\xBF")
>  
>       writer = csv.writer(response, delimiter=',')
>       …
>  
[/code]

* * *

> **2.DBが空欄だった場合も列を認識し、各項目をそろえて書き出しできる方法をご指導いただきたい**

そして上記の質問記事の方に、2.への対策らしき処理が見受けられます。

>
[code]

>     writer = csv.writer(response, delimiter=',')
>  
>     for row in qs.values_list(*self.fields_to_export):
>       writer.writerow([unicode(v).encode('utf-8') if v is not None else ''
> for v in row])
>  
[/code]

有効な値があれば(Noneでなければ)それを使い、無ければ(Noneなら)空文字列を値とするようです。

[code]

    unicode(v).encode('utf-8') if v is not None else ''
    
[/code]

これはデータベースの行をそのまま出力するから使える技でしょうか。

質問者さん記事のようにフィールドを選んで(or並び変えて？)出力する場合にどうするかは別として、考え方は使えるのでは？

あるいは、データベースのフィールドの定義を変えられるのなら以下の記事が参考になるかもしれません。  
[Djangoモデルフィールドのnullとblankの違いを理解する](https://djangobrothers.com/blogs/django_null_blank/)  
[DjangoのModelのFieldのオプション null と blank
の違いについて](https://thinkami.hatenablog.com/entry/2018/06/21/082731)  
[differentiate null=True, blank=True in
django](https://stackoverflow.com/questions/8609192/differentiate-null-true-
blank-true-in-django)  
[Model field reference |
Django](https://docs.djangoproject.com/en/2.0/ref/models/fields/)  
[Django
Modelを使ってみよう](https://eiry.bitbucket.io/tutorials/tutorial/models.html)  
[(Django) Allow NULL for certain model filed with blank and
null](https://medium.com/@bramblexu/django-allow-null-for-certain-model-filed-
with-blank-and-null-b0f402eeca7e)  
[Django Tips #8 Blank or
Null?](https://simpleisbetterthancomplex.com/tips/2016/07/25/django-
tip-8-blank-or-null.html)

それから、上記[DjangoのModelのFieldのオプション null と blank
の違いについて](https://thinkami.hatenablog.com/entry/2018/06/21/082731)で、手段はSQLite3のCLIですが、確認のために`NULL`の値を'NULL'という文字列に変えて出力する操作を行っています。

[code]

    # NULLの場合は、"NULL" という文字を出力
    # こうしないと、空文字とNULLの違いが分からないため
    sqlite> .nullvalue NULL
    
[/code]

これと同様のことが、個々のフィールドに対してDjangoあるいはMariaDBのプログラム/定義などで指定できるならば、それを使えるのでは？


CC BY-SA 4.0
2019-12-11T23:34:46.423
61354
2019-12-11T23:40:38.743
2020-06-17T08:14:45.997
-1
26370
61344
answer