3
2

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】アップロードされたcsvをpandasで処理して返却する

Last updated at Posted at 2021-06-26

はじめに

pythonでのデータ処理、機械学習を勉強中の初心者です。

今回は作成した回帰モデルを用い、アップロードされたテストファイルを読み込み、Notebookで行うようなpandasでのデータ処理を行った結果のcsvファイルをweb上でダウンロードする機能を持つアプリを作成しました。

その際にcsvの読み込み、返却ができるまでかなり詰まったので記録します。

ネット上にはDjangoでpandasを使う方法があまり見当たらず、いろいろと調べて試しながら完全に自己流で作ったので至らぬ点もあるかとは思いますがご容赦ください。

環境と前提

Windows10
django 3.1.7
python 3.9.2

  • プロジェクト作成
$ django-admin startproject myproject
$ cd myproject
$ python manage.py startapp app
  • ディレクトリ構成
myproject/
  app/
    __pycache__/
    migrations/
    static/
      files/ (new)
        train_x.csv
        train_y.csv
    __init__.py
    admin.py
    apps.py
    forms.py (new)
    functions.py (new)
    models.py
    tests.py
    views.py
  myproject/
    __pycache__/
    __init__.py
    asgi.py
    settings.py
    urls.py
    wsgi.py
static/
templates/
  index.html
db.sqlite3
manage.py

  • 目標イメージ
    image.jpg

フォームの作成

forms.pyを作成します。

forms.py
from django import forms

class UploadForm(forms.Form):
    testfile = forms.FileField()

これをhtmlで使うとファイルを選択するフォームが生成

index.html
<div class="form-group">
  <form method="POST" class="form" enctype="multipart/form-data">  
    {% csrf_token %}  
    <div class="file-upload-wrapper">
      <p>テストファイルを選択<br \>
        {{ form.testfile }}
      </p>   
    </div> 

最後にurls.pyの設定

urls.py
from django.contrib import admin
from django.urls import path
from app import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.index, name='index'), (追加)
]

settings.pyの設定

settings.py
# 省略

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app', # 追加
]
# 省略
TEMPLATES = [
    {
        # 省略
        'DIRS': [BASE_DIR, 'templates'],
        # 省略
    },
]

$python manage.py runserver実行後ローカルホストにアクセスするとファイル選択のフォームができています。

アップロードされたファイルの処理

今回はfunctions.pyにファイル処理の関数を書き、それをviews.pyで使っていきます。

views.py
from django.shortcuts import render
from django.http import HttpResponse
from django.template import loader
from app.forms import UploadForm
from app.functions import process_file,to_csv
import csv,io
import pandas as pd

# Create your views here.
def index(request):
    if request.method == 'POST':
        upload = UploadForm(request.POST, request.FILES)
        if upload.is_valid():
            data = pd.read_csv(io.StringIO(request.FILES['testfile'].read().decode('utf-8')), delimiter=',')
            df = process_file(data)

            response = to_csv(df)

            return response
    else:
        upload = UploadForm()
        return render(request, "index.html", {'form':upload})
  • data = pd.read_csv(io.StringIO(request.FILES['testfile'].read().decode('utf-8')), delimiter=',')

  • 単にpd.read_csvだけでは読み取れず、いろいろ試しまくった結果これでcsvの読み取りができました。

  • process_file():pandasでデータを処理

  • to_csv():データフレームをcsvファイルにしてダウンロード

データの処理、ダウンロード

functions.py
import pandas as pd
import numpy as np
import sklearn,csv,re,os
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from django.http import HttpResponse
from myproject.settings import BASE_DIR

def process_file(data):
    train_x = pd.read_csv(os.path.join(BASE_DIR, 'app/static/files/train_x.csv'))
    train_y = pd.read_csv(os.path.join(BASE_DIR, 'app/static/files/train_y.csv'))
    test = data
    
    # 自由にデータ処理

    # 最後にデータフレームとして返す
    df_result = ...

    return df_result

def to_csv(df):
    response = HttpResponse(content_type='text/csv; charset=UTF-8')
    response['Content-Disposition'] = 'attachment; filename="result.csv"'
    
    df.to_csv(path_or_buf = response, encoding = 'utf-8-sig', index=False)
    
    return response
  • データ処理に必要なモジュールをそれぞれインポート

  • process_file()

    • trainデータをmyproject/app/static/files/から読み込み
    • ローカルではpd.read_csv("app/static/files/~")でも可能
    • サーバーにデプロイするときはBASE_DIR/app/static/files/~となるように設定
    • (ちなみにBASE_DIRはsettings.pyで定義され、デフォルトではmanage.pyの存在するディレクトリ。この例ではmyproject/になります。)
    • Notebookで行っているような処理を自由に、最後にデータフレーム型で返してあげます。
  • to_csv()

    • process_fileから返却されたデータフレームをcsvに変換しダウンロード
    • HttpResponseとして"result.csv"という名前のcsvファイルを返す
    • attachmentをつけることで、フォームのボタンをクリックすると自動的にダウンロードが開始
    • path_or_buf = responseとすることでデータフレームをcsvに変換できるように
index.html
<div class="form-group">
  <form method="POST" class="form" enctype="multipart/form-data">  
    {% csrf_token %}  
    <div class="file-upload-wrapper">
      <p>テストファイルを選択<br \>
        {{ form.testfile }}
      </p>
    </div> 
    <p>テストファイルをアップロードし、予測結果の'result.csv'ファイルをダウンロードする</p>
    <button type="submit" class="save btn btn-outline-primary">Upload and Download</button>  
  </form> 
</div>

フォームボタンをつけて完成

補足

  • アップロードされたファイルの形式チェック等は省略しています。

  • Djangoでpandasを使用する方法を調べていると、django-pandasというライブラリをインストールして使うという説明しか見当たらなかったのですが、python標準モジュールのpandasでもなんとかできました。

3
2
0

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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?