Django’s default behavior is to run with an open transaction which it commits automatically when any built-in, data-altering model function is called. For example, if you call model.save() or model.delete(), the change will be committed immediately.Isso quer dizer que caso haja um erro durante a transação no banco de dados as transações subsequentes também não serão executadas. Este comportamento poder ser útil em alguns casos, mas não todos! Mas o django como sempre lhe dá liberdade para alterar o comportamento padrão, e geralmente de uma maneira muito simples. Este é o caso.
Vamos supor que queremos inserir 100 registros novos no banco de dados Postgres que foram lidos de um excel.
E no 10º registro ocorra em um campo string que exceda o tamanho do campo no banco de dados, como abaixo
* DatabaseError('value too long for type character varying(70)
* DatabaseError('current transaction is aborted, commands ignored until end of transaction block
...
* DatabaseError('current transaction is aborted, commands ignored until end of transaction block]
o primeiro erro é por causa de uma string maior do que a aceita pelo campo no banco de dados.
Os error subsequentes, ocorreram simplesmente porque houve um erro ! oops, confuso?
veja a primeira mensagem de error
- mensagem 1 - value too long for type character varying(70)
- mensagem 2 em diante - current transaction is aborted, commands ignored until end of transaction block
a partir da msg de erro 2, o que temos é um erro de transação pendente, porque o commit automático não ocorreu.
O código executado é algo parecido com isso abaixo
for row_index in range(20 ): try: model_instance.save() # salvar o modelo except Exception, error_str: error_list.append(error_str)
No meu caso, eu quero continuar as inserções no banco, mesmo que haja erro em algumas delas.
A saida é fazer um Savepoint Rollback! THANKS DJANGO !
Savepoint rollbackO que é dito aqui, é que ao salvar um ponto de rollback, eu posso comitar as transações que ocorreram sem erro, e dar um "rollback" somente na transação que falhou.
If you are using PostgreSQL 8 or later, you can use savepoints to control the extent of a rollback. Before performing a database operation that could fail, you can set or update the savepoint; that way, if the operation fails, you can roll back the single offending operation, rather than the entire transaction.
O código ficaria assim
for row_index in range(20 ): try: sid = transaction.savepoint() # salvar ponto da transação model_instance.save() # salvar o modelo transaction.savepoint_commit(sid) # aplicamos o commit da transação except Exception, error_str: error_list.append(error_str) transaction.savepoint_rollback(sid) #rollback somente da transação que falhou
leia mais na docs do Django em : http://docs.djangoproject.com/en/1.3/topics/db/transactions/