Это руководство для новичков в Django, которые прочитали начальное руководство по Django на официальном сайте и столкнулись с задачей загрузки csv файла с таблицей в базу данных
В этом случае, у вас есть приложение polls, с урлами, моделями, вьюшками для классов вопросов (Question) и ответов (Choices). И база данных с сгенерированными таблицами (polls_question, polls_choice)
Для примера, будем загружать в базу данных csv файл с вопросами (Questions).
Назовем файл questions_01a.csv и поместим туда такое содержимое:
Why?,2022-11-14 10:00 For what?,2022-11-14 10:01 When?,2022-11-14 10:02 Where?,2022-11-14 10:03
Перенос строк — как разделитель информации по вопросам, и запятая — как разделитель ячеек данных
Изменения в /polls/urls.py:
from django.urls import path from . import views app_name = 'polls' urlpatterns = [ … path('upload_csv/', views.upload_csv, name='upload_csv'), ]
Изменения в /polls/views.py:
from django.http import HttpResponseRedirect from django.shortcuts import render, get_object_or_404 from django.urls import reverse from django.views import generic from django.utils import timezone from django.contrib import messages from .models import Question, Choice … def upload_csv(request): data = {} if "GET" == request.method: return render(request, "polls/upload.html", data) # if not GET, then proceed try: csv_file = request.FILES["csv_file"] if not csv_file.name.endswith('.csv'): messages.error(request, 'File is not a CSV') return HttpResponseRedirect(reverse("polls:upload_csv")) # if file is too large - error if csv_file.multiple_chunks(): messages.error(request, "Uploaded file is too big (%.2f MB). " % (csv_file.size/(1000*1000),)) return HttpResponseRedirect(reverse("polls:upload_csv")) file_data = csv_file.read().decode("utf-8") lines = file_data.split("\n") # loop over the lines and save them to db via model for line in lines: fields = line.split(",") try: question = Question( question_text=fields[0], pub_date=fields[1], ) question.save() except Exception as e: messages.error(request, "Unable to upload file. "+repr(e)) pass except Exception as e: messages.error(request, "Unable to upload file. "+repr(e)) return HttpResponseRedirect(reverse("polls:upload_csv"))
Что делаем в views.py:
- Импортируем стандартный фреймворк сообщений (messages), чтобы можно было на страничке выводить ошибки
- Файл будем посылать методом POST, если же запрос GET — открываем страницу аплода
- Делаем простые проверки получаемого файла (тип файла и максимальный размер)
- Читаем построчно и сохраняем в базу данных, через модель
Создаем страничку для загрузки файла — /polls/templates/polls/upload.html со следующим кодом:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Upload</title> <link href="https://netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <form action="{% url "polls:upload_csv" %}" method="POST" enctype="multipart/form-data" class="form-horizontal"> {% csrf_token %} <div class="form-group"> <label for="name" class="col-md-3 col-sm-3 col-xs-12 control-label">File: </label> <div class="col-md-8"> <input type="file" name="csv_file" id="csv_file" required="True" class="form-control"> </div> </div> <div class="form-group"> <div class="col-md-3 col-sm-3 col-xs-12 col-md-offset-3" style="margin-bottom:10px;"> <button class="btn btn-primary"> <span class="glyphicon glyphicon-upload" style="margin-right:5px;"></span>Upload </button> </div> </div> {% if messages %} <ul class="messages"> {% for message in messages %} <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li> {% endfor %} </ul> {% endif %} </form> </body> </html>
Что делаем в upload.html:
- Минималистичная html страница
- Подключаем стили бутстрап для более-менее симпатичного отображения элементов
- Форма с кнопкой Загрузки
- CSFR токен для защиты формы от размещения ее на внешних источниках, чтобы украсть ваши данные (стандартная защита)
- Блок для отображения ошибок messages
Запускаем проект и пробуем открывать страничку
http://127.0.0.1:8000/polls/upload_csv/
Загружаем наш заранее заготовленный файл questions_01a.csv и проверяем базу данных на наличие новых строк
Выглядит это так: