Как преобразовать команды управления Django в действия формы, чтобы заполнить базу данных загруженным CSV-файлом?

Django 1.9.8, Python 3.6, база данных Postgres

Я пишу небольшое приложение на Django, которое будет использовать пользовательский интерфейс для импорта товаров из загруженного файла csv через Form и заполнения базы данных. Я написал логику бэкенда для приложения, используя Custom Management Commands, но не могу понять, как подключить его к фронтенду, используя Forms.

Вот пример файла csv:

name,sku,description
Brian James,skus-will-look-like-this,The products will have various descriptions. And multiple lines too.

У меня реализована следующая логика:

  1. Read a large csv file of 500K products to the database using SKU as a unique field.
  2. When the file has uploaded, a live stream of what is happening should be displayed. print() currently serves this purpose but I think it should be possible to implement this with SSE on the front end.
  3. All products can be searched / filtered.
  4. Be able to delete all existing records and start a fresh upload as well as being able to add/update products manually.

Я создал простой загрузчик форм как отдельный проект, чтобы поиграть с ним, но даже после этого и чтения docs я не понимаю, как перейти от "преобразования" команд управления в жизнеспособные действия через Forms.

Вот соответствующий код:

Это загружает локальный файл csv, анализирует его, обновляет только определенные поля, если SKU уже существует, создает статус 'активный/неактивный', и печатает после каждого сохранения, чтобы пользователь мог видеть, что происходит.

/products/management/commands/import_products.py

class Command(BaseCommand):

    def handle(self, *args, **options):

        print('Importing data from:', settings.DATA_IMPORT_LOCATION)

        with open(f'{settings.DATA_IMPORT_LOCATION}/products.csv', 'r') as products_csv:
            products_file = csv.reader(products_csv)
            next(products_file)  # skip header row

            for counter, line in enumerate(products_file):
                name = line[0]
                sku = line[1]
                description = line[2]

                # Check if sku already exists if this just needs to be updated
                if Product.objects.filter(sku=sku).exists():
                    sku_id = Product.objects.only('id').get(sku=sku).id
                    p = Product(id=sku_id)
                    p.name = name
                    p.description = description
                    p.status = random.choice(['active', 'inactive'])
                    p.save(update_fields=['name', 'description', 'status'])
                    print(p)

                else:
                    p = Product()
                    p.name = name
                    p.sku = sku
                    p.description = description
                    p.status = random.choice(['active', 'inactive'])
                    p.save()
                    print(p)

            print(f'Import complete, imported {counter} products')

Это удаляет все объекты из базы данных /products/management/commands/delete_products.py

from products.models import Product
from django.core.management.base import BaseCommand

class Command(BaseCommand):
    def handle(self, *args, **options):
        Product.objects.all().delete()

models.py

class Product(models.Model):
    name = models.TextField(blank=False, null=False)
    sku = models.TextField(blank=False, null=False, unique=True)
    description = models.TextField(blank=False, null=False)
    status = models.TextField(blank=False, null=False, default='inactive')

    def __str__(self):
        return [self.name, self.sku, self.description, self.status]

Я должен быть в состоянии сделать что-то вроде этого:

Добавьте document = models.FileField(upload_to='documents/') в models.py

Добавьте forms.py

from django import forms
from models import Product

class ProductForm(forms.ModelForm):
    class Meta:
        model = Product
        fields = ('name', 'sku', 'description', 'status', 'document')

/templates/products/model_form_upload.html

{% extends 'base.html' %}

{% block content %}
  <form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Upload</button>
  </form>

  <p><a href="{% url 'home' %}">Return home</a></p>
{% endblock %}

/templates/products/home.html

{% extends 'base.html' %}

{% block content %}
  <ul>
    <li>
      <a href="{% url 'model_form_upload' %}">Model Form Upload</a>
    </li>
  </ul>

  <p>Uploaded files:</p>
  <ul>
    {% for obj in products %}
      <li>
        <a href="{{ obj.product.url }}">{{ obj.product.name }}</a>
        <small>(Uploading: {{ obj.name }})</small>
      </li>
    {% endfor %}
  </ul>
{% endblock %}

Добавление этого в views.py:

def home(request):
    products = Product.objects.all()
    return render(request, 'products/home.html', { 'products': products })

def model_form_upload(request):
    if request.method == 'POST':
        form = ProductForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('home')
    else:
        form = ProductForm()
    return render(request, 'products/model_form_upload.html', {
        'form': form
    })

Добавление к urls.py:

urlpatterns = [
url(r'^$', views.home, name='home'),
url(r'^uploads/form/$', views.model_form_upload, name='model_form_upload'),
]

И добавляем это в settings.py:

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

Добавление этого кода приводит к сбою приложения и многочисленным ошибкам (неправильно настроенные урлы, страница не загружается, данные не сохраняются и т.д.). Я не уверен, как интегрировать Form с логикой из Management Commands так, чтобы csv файл, загруженный через Form действительно был "схвачен" и разобран, как это происходит в import_products.py -> with open(f'{settings.DATA_IMPORT_LOCATION}/products.csv', 'r') as products_csv:

Буду признателен за любую помощь или за направление к каким-либо источникам, которые рассматривают этот рабочий процесс CRUD операций с Forms.

Вернуться на верх