Как создать экземпляры модели из файла CSV - PullRequest
1 голос
/ 18 февраля 2020

Есть задача проанализировать файл csv и создать экземпляры в базе данных на основе полученных данных. На бэкэнде - DRF, а на передней - React. Особенность c в том, что обработка файла не совсем скрыта. Лог c выглядит следующим образом: есть кнопка для загрузки файла. Файл загружается и проверяется, но в базе данных ничего не создается сразу. Появится окно со списком сохраненных данных (например, таблицы), и в этом окне есть новая кнопка для подтверждения, нажав на которую база данных уже запрошена.

Что я только что сделал: 1. Создал класс для загрузки файла (кнопка «Загрузить»)

class FileUploadView(APIView):
    parser_classes = ( MultiPartParser, FormParser)
    renderer_classes = [JSONRenderer]

    def put(self, request, format=None):
        if 'file' not in request.data:
            raise ParseError("Empty content")
        f = request.data['file']
        filename = f.name
        if filename.endswith('.csv'):
            file = default_storage.save(filename, f)
            r = csv_file_parser(file)
            status = 204
        else:
            status = 406
            r = "File format error"
        return Response(r, status=status)

В классе вызывается функция csv_file_parser , результатом которой является json, содержащая все сохраненные данные, например:

{
    "1": {
        "Vendor": "Firstvendortestname",
        "Country": "USA",
         ...
         ...
        "Modules": "Module1",
        " NDA date": "2019-12-24"
    },
    "2": {
        "Vendor": "Secondvendortestname",
        "Country": "Canada",
         ...
         ...
        "Modules": "Module1",
        " NDA date": "2019-12-24"
    }
}

Эти данные будут использоваться для предварительного просмотра полей, из которых будут создаваться модели в базе, путем нажатия кнопки Подтвердить .

csv_file_parser function

def csv_file_parser(file):
    result_dict = {}
    with open(file) as csvfile:
        reader = csv.DictReader(csvfile)
        line_count = 1
        for rows in reader:
            for key, value in rows.items():
                if not value:
                    raise ParseError('Missing value in file. Check the {} line'.format(line_count))
            result_dict[line_count] = rows
            line_count += 1


    return result_dict

Когда нажата кнопка «Подтвердить», React передает эти данные в качестве аргумента классу, который работает с базой данных, используя метод POST. С реализацией этого класса у меня возникли трудности. Как правильно обработать полученные данные и записать их в базу данных?

class CsvToDatabase(APIView):

    def post(self, request, format=None):
        data = request.data
        for vendor in data:
            Vendors(
                vendor_name=vendor['Vendor'],
                country=vendor['Country']
            ).save()


        return Response({'received data': request.data})

Этот код выдает ошибку

TypeError at /api/v1/vendors/from_csv_create/
string indices must be integers

Печать request.data output

<QueryDict: {'{\n    "1": {\n        "Vendor": "Firstvendortestname",\n        "Country": "USA",\n        "Primary Contact Name": "Jack Jhonson",\n        "Primary Contact Email": "jack@gmail.com",\n        "Secondary Contact Name": "Jack2 Jhonson",\n        "Secondary Contact Email": "jack2@gmail.com",\n        "Modules": "Module1, Module2",\n        " NDA date": "2019-12-24"\n    },\n    "2": {\n        "Vendor": "Secondvendortestname",\n        "Country": "Canada",\n        "Primary Contact Name": "Sandra Bullock",\n        "Primary Contact Email": "sandra@gmail.com",\n        "Secondary Contact Name": "Sandra Bullock",\n        "Secondary Contact Email": "sandra@gmail.com",\n        "Modules": "Module1, Module2",\n        " NDA date": "2019-12-24"\n    }\n}': ['']}>

Может быть, я использую неправильный формат данных?

И в целом у меня есть ощущение, что я делаю работу неправильно. Я не использую сериализаторы, они мне нужны здесь?

Ответы [ 2 ]

1 голос
/ 18 февраля 2020

Прежде всего, я предлагаю использовать массовую операцию создания, а не создавать их один за другим. Пожалуйста, перейдите по этой ссылке документации https://docs.djangoproject.com/en/3.0/ref/models/querysets/#bulk -создать .

Ваша проблема вызвана тем, что вы неправильно следите за данными в вашем l oop. Мой совет - начать поиск проблемы с ошибок. Ошибка ясно говорит о том, что ошибка находится в структуре данных.

Теперь давайте посмотрим на request.data, это не список, содержащий указания для l oop их, как вы делаете там. Пожалуйста, смотрите эту страницу StackOverflow для более подробной информации: Извлечение элементов из QueryDict

1 голос
/ 18 февраля 2020

Вы перебираете ключ dict, но должны перебирать элементы:

   for key, vendor in data.items():
        Vendors(
            vendor_name=vendor['Vendor'],
            country=vendor['Country']
        ).save()
...