2016-04-29 3 views
4

Я создаю приложение Django, где пользователи будут импортировать файл Excel/CSV. Каждая строка подается через форму, как описано here (пример 3 внизу).Использование транзакций в Django при импорте файлов

Для моего импортера я сначала просматриваю весь файл, и я отображаю любые ошибки в таблице. Если ошибок нет, я покажу резюме того, что будет импортировано. Пользователь может подтвердить, и файл будет импортирован. Проблема в том, что строки зависят друг от друга для проверки (ограничения уникальности и т. Д.), Поэтому я должен сохранить каждую строку в БД для проверки правильности работы.

Я придумал подход ниже, но раньше я не использовал атомные транзакции, и я беспокоюсь о потенциальных ошибках. Я мог бы импортировать до 10 000 рядов.

Является ли код ниже штрафом за то, что я хочу достичь, или есть лучшие методы?

def import_from_csv(filename, preview): 
    sid = transaction.savepoint() 
    result = import_data(filename) 
    if result.has_error or preview: 
     transaction.savepoint_rollback(sid) 
    else: 
     transaction.savepoint_commit(sid) 
    return result 

Дополнительная информация:

В моем приложении есть имеет два вида окрености. Первый вид - просмотр. В этом случае я вызываю import_from_csv с параметром предварительного просмотра, равным True. Таким образом, вставки всегда будут откатны. Он возвращает результаты того, что было бы импортировано. Если ошибок нет, я сохраняю местоположение файла в переменной сеанса. Если пользователь нажимает кнопку подтверждения, я снова вызываю import_from_csv, но на этот раз предварительный просмотр False. Поскольку я уже проверил файл на этапе предварительного просмотра, ошибок не должно быть и результаты будут выполнены. Я знаю, что это можно оптимизировать, так как я обрабатываю файл дважды.

Я использую Django 1.9 и Postgres (на Heroku)

+1

Какую версию Django вы используете? Если это современная версия, вы должны использовать 'transaction.atomic', если у вас нет веской причины. –

ответ

2

Gotcha 1

Вставка 10000 строк не собирается, чтобы быть очень быстрым, независимо от того, что база данных. Вы можете просто сжать его до таймаутов, но у вас есть шанс.

Гоча 2

В транзакции после того, как произошла ошибка, что транзакция не может быть использована для дальнейших вставок, пока Вы не откатить. Если вторая строка в вашей CSV вызывает ошибку, вы обнаружите, что ничего не вставлено.

на основе обновленной информации:

Вы бы до сих пор трудно понять, какие записи могут быть вставлены и что не может быть. Возможно, вам понадобится auto commit в import_data, что еще больше замедлит работу.

Гоча 3

подход фактически не обеспечивают и возможность для пользователя, чтобы подтвердить или отклонить вставку. Действие пользователя будет обработано отдельным HTTP-запросом. Он будет отличаться от того, который отправил CSV-данные. В результате к тому времени, когда пользовательское действие будет получено, эта транзакция завершена и вычищена и не может быть отброшена.

Гоча 4

Если раньше строки зависит от последних строк (вы сказали, что, возможно, отношения между рядами) вставка будет выполнена.

Решение

насыпной Использование базы данных загрузки для заполнения временной таблицы, которая идентична реальной вещи за контрсилами исключением. Вы не указали, что такое ваша база данных. Например, путь к массовой загрузке в postgresql равен COPY FROM, а в mysql - LOAD DATA.

Добавьте ограничения во временную таблицу после загрузки данных. Соединитесь с исходной таблицей, чтобы определить, какие строки дублируются. Попросите пользователя игнорировать или обновлять дубликаты. Тогда не ВСТАВИТЬ ВЫБРАТЬ

Ответ на дополнительную информацию:

Если вы используете сельдерей задачи, не может зависеть от COPY, но он все равно будет лучше, чтобы сделать начальный импорт во временную таблицу , Таким образом, вы избегаете необходимости обрабатывать данные дважды. И очень легко понять, какие строки в файле CSV приводят к дублированию.

+0

Спасибо за отличный ответ. 1. Хорошая точка, я переведу ее на задание на сельдерей 2. Если есть ошибка, не отбросит ли она и ничего не будет вставлено? Я хочу, чтобы либо все записи, либо ни одна из записей не была вставлена ​​3. Я не объяснил это достаточно хорошо, я отредактировал свой вопрос, чтобы дать больше информации. Учитывая обновление, вы все еще думаете, что COPY FROM - лучший подход? Я довольно новичок в Django и не хочу, чтобы я упал до необработанного sql, если только не должен. – Johan

+0

пункт 2: oops извините, мой плохой исправленный и также обновлен в ответ на ваш вопрос – e4c5

Смежные вопросы