[pyar] Actualizando estado de carga de datos con Django y Celery

Marcelo Leiva Sandoval chelitoleiva en gmail.com
Lun Jul 25 12:22:54 ART 2016


Muchas gracias por tu respuesta Carlos voy a realizar cambios y te comento como me fue, saludos.

Marcelo Leiva Sandoval

Sent from
https://polymail.io/

On lun, 25 de jul de 2016 at 08:39 "Carlos Matías"

<
mailto:
> wrote:

_______________________________________________

pyar mailing list
mailto:pyar en python.org.ar http://listas.python.org.ar/listinfo/pyar
PyAr - Python Argentina - Sitio web:
http://www.python.org.ar/
La lista de PyAr esta Hosteada en USLA - Usuarios de Software Libre de Argentina -
http://www.usla.org.ar

Hola, un par de comentarios que capaz alguno te sirva:

1) 

procesar_csv_task.delay(instance)

Ojo con pasar directamente una instancia de modelo Django a las tasks de Celery. Típicamente se pasa un pk y dentro de la tarea tendrías que obtener la instancia correspondiente: 
http://docs.celeryproject.org/en/latest/userguide/tasks.html#state

2) 

cantidad_registros = len(list(clientes))

 # si realizo esto la tarea termina

DictReader es un iterator. En esa línea lo estás recorriendo entero. Más adelante, en un for estás queriendo re-recorrerlo pero el iterador está exhausto: 
https://docs.python.org/3.4/glossary.html#term-iterator

Ya que estás convirtiendo el iterador

clientes

en una lista, podrías guardarlo para re-utilizar esa lista.

3) Hay muchas cosas que podés hacer para resolver el tema de mostrar cada 100 registros. Por ejemplo, en el post-save solamente encola 

procesar_csv_task

 si

existe_archivo and instance.porcentaje_carga == 0

y dentro de la task te encargás de actualizar ese campo cuando haga falta (al inicio lo ponés en 1 y después, cada 100 registros, lo volvés a actualizar).

Suerte con eso

 

---------- Forwarded message ----------

From: Marcelo Leiva Sandoval <
mailto:chelitoleiva en gmail.com
>

To: Python Argentina <
mailto:pyar en python.org.ar
>

Cc: 

Date: Sat, 23 Jul 2016 14:42:25 -0300

Subject: [pyar] Actualizando estado de carga de datos con Django y Celery

Buenas tardes, tengo una vista donde de sube al servidor un archivo csv (más de 50.000 registros) para realizar una carga masiva de datos. Actualmente este archivo se guarda en /media/ y en con el signal post_save() se ejecuta una tarea en Celery para realizar la carga de información. 

Esto funciona bastante bien, pero ahora necesito mostrar el estado de avance de la carga de datos en el mismo modelo donde se encuentra el archivo csv.

# models.py

class

ArchivoCSV

(models.Model):

nombre = models.CharField(

verbose_name

=

'Nombre del archivo'

,

max_length

=

200

,

editable

=

False

)

archivo = models.FileField(

upload_to

=PATH_CSV_PREDIOS

,

max_length

=

800

)

porcentaje_carga = models.PositiveIntegerField(

verbose_name

=

'Porcentaje de carga'

,

default

=

0

,

validators

=[MaxValueValidator(

100

)

,

MinValueValidator(

0

)]

,

editable

=

False

)

estado = models.CharField(

verbose_name

=

'Estado de carga'

,

choices

=ESTADOS_CARGA

,

default

=

'S'

,

max_length

=

1

,

editable

=

False

)

creado_el = models.DateTimeField(

auto_now_add

=

True

)

modificado_el = models.DateTimeField(

auto_now

=

True

)

history = HistoricalRecords()

class

Meta

:

verbose_name_plural =

"Cargar archivo CSV."

ordering = [

'-creado_el'

]

def

__str__

(

self

):

return

'{0}'

.format(

self

.nombre)

def

save

(

self

,

*args

,

**kwargs):

if not

self

.pk:

self

.nombre =

self

.archivo

super

(ArchivoCSV

,

self

).save(*args

,

**kwargs)

def

delete

(

self

,

using=

None

):

archivo =

self

.
http://archivo.name
super

(ArchivoCSV

,

self

).delete()

existe_archivo = os.path.exists(archivo)

if

existe_archivo:

try

:

os.remove(archivo)

except

Exception

as

e:

print

(e)

@

receiver

(post_save

,

sender

=PredioCSV)

def

procesar_archivo_post_save

(

sender

,

**kwargs):

instance = kwargs[

'instance'

]

existe_archivo = os.path.exists(
http://instance.archivo.name
)

if

existe_archivo:

from

.tasks

import

procesar_csv_task

procesar_csv_task.delay(instance)

En el task si agrego cantidad_registros = len(list(clientes)) la tarea termina. Y si actualizo la instancia la tarea se multiplica infinitamente.

# tasks.py

@

app.task

(

ignore_result

=

True

,

name

=

"cargando-csv"

)

def

procesar_csv_task

(instance):

nuevos_clientes = []

listado_clientes = Cliente.objects.all()

encoding = determinar_encoding(

open

(
http://instance.archivo.name
,

"rb"

).read())

if

encoding:

clientes = DictReader(

open

(
http://instance.archivo.name
,

"rb"

)

,

delimiter

=

';'

,

encoding

=encoding

,

skipinitialspace

=

True

)

cantidad_registros =

len

(

list

(clientes))

# si realizo esto la tarea termina

try

:

for

index

,

row

in

enumerate

(clientes

,

start

=

1

):

try

:

codigo = row[

'COD_CLIENTE'

]

...

if

listado_clientes.filter(

codigo

=codigo).first():

# se editan datos del cliente

else

:

nuevo_cliente = Cliente()

...

nuevos_clientes.append(nuevo_cliente)

except

Exception

as

e:

print

(e)

if

index %

100

==

0

:

instance.porcentaje_carga = index *

100

/ cantidad_registros

# con esto la tarea se multiplica

instance.save()

Cliente.objects.bulk_create(nuevos_clientes)

except

Exception

as

e:

print

(e)

else

:

print

(

'No se puede definir el encodig del archivo csv.'

)

La idea es cada 100 registros trabajados actualizar el modelo con el porcentaje de avance y luego de ejecutar el bulk_create cambiar el estado a finalizado. Quedo atento a sus preguntas y sugerencias.

Saludos

--

Marcelo Leiva Sandoval

Django & Symfony2 Developer

Linux User #491264

--

Carlos Matías
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.python.org.ar/pipermail/pyar/attachments/20160725/99986b71/attachment-0001.html>


Más información sobre la lista de distribución pyar