Django: import-export で、csvファイルを読み込む

Django-import-exportでcsvのインポート・エクスポートが出来る

Djangoの学習をしながら、現在運営しているオンライン英会話スクールの生徒管理アプリをコツコツ作成中です(完成するのだろうか。。。)

生徒氏名・受講クラス・登録日・更新日・誕生日をcsvで読み込んで、表示させる

models.py コースと生徒さんのモデルを作成

●Courses にテキストとページ(unit)を含める

●将来的にデータベースを、変更する可能性があります(レッスン評価などを追加予定)。

●こちらのサイトを参考にさせて頂きました:https://blog.fragment.co.jp/code/python/django/django-import-export/

from django.contrib.auth.models import AbstractUser
from django.db import models
# Create your models here.

class User(AbstractUser):
    pass


class Courses(models.Model):
    id = models.AutoField(primary_key=True)
    course_name = models.CharField(max_length=50)
    textbook_read = models.CharField(max_length=50)
    textbook_write = models.CharField(max_length=50)
    textbook_listening = models.CharField(max_length=50)
    textbook_speaking = models.CharField(max_length=50)
    unit = models.IntegerField(null=True, blank=True)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    def __str__(self):
	    return f"{self.course_name}: {self.textbook_read}, {self.textbook_write}, {self.textbook_listening}, {self.textbook_speaking}"


class Students(models.Model):
    id = models.AutoField(primary_key=True)
    student_name = models.CharField(max_length=50)
    course_name = models.ForeignKey(Courses, on_delete=models.PROTECT, default=1)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    dob = models.DateField(max_length=8, null=True, blank=True)


    class Meta:
           ordering = ['student_name']


    def __str__(self):
        return f"{self.student_name} | {self.course_name}"

●class Meta で、読み込んだ生徒リストがアルファベット表示されるようにしています。

views.py

●リスト表示・インポート・エクスポート設定をしています。

from django.http import HttpResponse
from django.urls import reverse_lazy
from django.views import generic
from django.shortcuts import redirect

import csv
import io
from .forms import StudentCsvForm
from .models import Students



class StudentIndex(generic.ListView):
    model = Students


class StudentImport(generic.FormView):
    template_name = 'student/import.html'
    success_url = reverse_lazy('index')
    form_class = StudentCsvForm

    def form_valid(self, form):
        form.save()
        return redirect('index')


def student_export(request):
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="students.csv"'
    writer = csv.writer(response)
    for student in Students.objects.all():
        writer.writerow([student.pk, student.student_name, student.score])
    return response

views.py

urls.py 一覧表示・インポート・エクスポート

後日、テキストcsv等も追加するので、urlには、student_import, student_export と名付けておく

from django.urls import path
from . import views

urlpatterns = [
    path('', views.StudentIndex.as_view(), name='index'),
    path('student_import', views.StudentImport.as_view(), name='student_import'),
    path('student_export', views.student_export, name='student_export'),
]

ちなみに、プロジェクトのurl.pyはこちら

from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('student.urls')),
]

forms.py インポート用のフォーム作成

from django.http import HttpResponse
from django.urls import reverse_lazy
from django.views import generic
from django.shortcuts import redirect

import csv
import io
from .forms import StudentCsvForm
from .models import Students



class StudentIndex(generic.ListView):
    model = Students


class StudentImport(generic.FormView):
    template_name = 'student/import.html'
    success_url = reverse_lazy('index')
    form_class = StudentCsvForm

    def form_valid(self, form):
        form.save()
        return redirect('index')


def student_export(request):
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="students.csv"'
    writer = csv.writer(response)
    for student in Students.objects.all():
        writer.writerow([student.pk, student.student_name, student.score])
    return response

base.html 共通設定・メニューバー

{% load static %}

<!DOCTYPE html>
<html lang="ja">

<head>
    <!-- Required Meta Tags -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
        integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    <!-- Custom CSS -->
    <link href="{% static 'student/styles.css' %}" rel="stylesheet">
    <!-- Font Awesome -->
    <script src="https://kit.fontawesome.com/bea7d521cb.js" crossorigin="anonymous"></script>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

    <!-- favicon -->
    <link rel="icon" href="{% static 'student/favicon.ico' %}">

    <title>{% block title %}{% endblock %}</title>
</head>

<body>

    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <a class="navbar-brand" href="{% url 'index' %}">Students</a>

        <div>
            <ul class="navbar-nav mr-auto">
                <li class="nav-item">
                    <a class="nav-link" href="{% url 'student_export' %}"><strong>Export Student</strong></a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="{% url 'student_import' %}"><i class="fab fa-pagelines"></i> Import Student</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">Log Out</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">Please Login</a>
                </li>
        </div>
    </nav>

    <div class="body">
        {% block body %}
        {% endblock %}
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
        crossorigin="anonymous"></script>
    <script src="https://code.jquery.com/jquery-3.5.0.js"
        integrity="sha256-r/AaFHrszJtwpe+tHyNi/XCfMxYpbsRg2Uqn0x3s2zc=" crossorigin="anonymous"></script>
</body>

</html>

student_import.html インポート用テンプレート作成

{% extends "student/base.html" %}

{% block title %} Student List {% endblock %}
{% block body %}
<div class="container" style="text-align: center;">
    <form action="" method="POST" enctype="multipart/form-data">
        {% csrf_token %}
        {{ form.as_ul }}
        <button type="submit">Submit</button>
    </form>
</div>
{% endblock %}

student_list.html 生徒一覧作成

Bootstrap Tables 使用

{% extends "student/base.html" %}

{% block title %} Students {% endblock %}
{% block body %}
<div class="container" style="text-align: center;">
    <h2 >Student List</h2><br>
    <h3>First Name Alphabetical Order</h3><br>
    <p><i class="fas fa-star-of-life star"></i> ID, Name, Course, Registered, Updated, Birthday <i class="fas fa-star-of-life star"></i></p>
        {% for student in students_list %}     
        <table class="table">
        <tbody>
            <tr>
            <td>#</td>
            <td>{{ student.id }}</td>
            <td>{{ student.student_name }}</td>
            <td>{{ student.course_name }}</td>
            <td>{{ student.created }}</td>
            <td>{{ student.updated }}</td>
            <td>{{ student.dob }}</td>
            </tr>
        </tbody>
        </table>
        {% endfor %}
    </table>
</div>
{% endblock %}

生徒リストcsvファイル準備

ダミーのcsvでテスト

生徒名をアルファベット順に出力しています。

●各コースに4種類のテキストをForeignKeyで紐づけているので、使用テキストも表示されています。

まとめ

models.py が入り組んでくると、上記のコードを微調整する必要があるみたいです。まだまだ学習不足なので、あと、いくつか試してみます。 現在、こちらの動画で学習中です。

おすすめ記事

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です