viernes, 27 de septiembre de 2019

Modificar Estado de Varios Registros al Mismo tiempo con Django y jquery



 http://bit.ly/DJFULL-BLOG12019

En este tutorial, veremos cómo poder cambiar el estado de un listado de Categorías de una sola vez, para eso haremos uso de jQuery en el FrontEnd para recoger todos los id's de las categorías y con Django en el BackEnd procesaremos la lista.

Nuestra plantilla luce algo así


La idea principal es poder seleccionar más de un registro y al dar click en el botón Inactivar/Activar poder cambiar el estado de todos los registros seleccionados.

La tabla se está renderizando como una tabla normal de html y bootstrap, de la siguiente forma:



Nota que en la última columna de la tabla está el checkbox, que tiene por nombre record, esto es importante porque así los filtraremos.

Para mostrar la información, tenemos el siguiente modelo:

 class Categoria(ClaseModelo):  
   descripcion = models.CharField(  
     max_length=150,  
     help_text='Descripción de la Categoría',  
     unique=True  
   )  
   def __str__(self):  
     return '{}'.format(self.descripcion)  
   def save(self):  
     self.descripcion = self.descripcion.upper()  
     super(Categoria, self).save()  
   class Meta:  
     verbose_name_plural= "Categorias"

Asumiré que ya hay registros y ya tienes toda la estructura de un proyecto, por tanto nos iremos a trabajar en el FrontEnd, en la plantilla que muestra la tabla y trabajaremos en el evento click del botón, el cual tiene como id btnInactivar,

 $("#btnInactivar").click(function(e){  
    e.preventDefault();  
    var ids = [];  
    $("table tbody").find('input[name="record"]').each(function(){  
      if($(this).is(":checked")){  
       var id = $(this).parents("tr").find("td").eq(0).html();  
       ids.push(id);  
      }  
    });  
 }); 

Como podemos ver, primeramente creamos un arreglo llamado ids, recorremos la tabla y buscamos los input que el name sea record, luego preguntamos si ese input tiene check, de tenerlo, tomamos el valor de la columna cero, la del id (var id = $(this).parents("tr").find("td").eq(0).html();) y agregamos el valor del id al arreglo  ids.push(id);.

Ya que tenemos capturados todos los ids, ahora pondré el evento click completo, donde puedes ver el uso de ajax que invoca una ruta, a la cual se le pasa la lista el arreglo de ids recopilados

 $("#btnInactivar").click(function(e){  
    e.preventDefault();  
    var ids = [];  
    $("table tbody").find('input[name="record"]').each(function(){  
      if($(this).is(":checked")){  
       var id = $(this).parents("tr").find("td").eq(0).html();  
       ids.push(id);  
      }  
    });  
    console.log(ids);  
    if(ids.length==0){  
     alert("Debe Seleccionar al menos un registro");  
     return false;  
    }  
    var token = '{{csrf_token}}';  
    var data = JSON.stringify({"ids":ids});  
    data = {"ids[]":ids};  
    //console.log(data);  
    $.ajax({  
     headers: { "X-CSRFToken": token },  
     url: "{% url 'inv:categoria_change_state' %}",  
     type: "POST",  
     data: data,  
     success: function(e){  
      if(e="OK"){  
       location.reload(true);  
      }  
     },  
     error: function(a,b,c){  
      alert(c);  
     }  
    });  
   });  


Lo importante de todo lo anterior es ver cómo se inicializa la variable data con el arreglo de ids.
var data = JSON.stringify({"ids":ids});
data = {"ids[]":ids};

Esta forma, es que recibirá Django en el BackEnd en forma de lista.

Otros datos importantes, el token csrf que debe ir incluido en toda petición POST hacia un backend en Django y la ruta que invoca (url: "{% url 'inv:categoria_change_state' %}") que aún no lo tenemos, pero ya iremos al backend.
Al finalizar, si todo bien, se hará una recarga de la página y listo, del lado del Front hemos terminado, sólo falta aclarar que en mi caso, esta plantilla se llama categoria_list_activate_many.html.

En el BackEnd, lo primero será crear una vista y para trabajar todo en la misma, haremos una vista de funciones, a la cual le declararemos dos variables conteniendo el nombre de la plantilla y un contexto vacío, bueno, no escribo más y te dejo la vista.

 from django.shortcuts import HttpResponse  
 def categoria_change_state(request):  
   template_name = "inv/categoria_list_activate_many.html"  
   contexto={}  
   if request.method=="GET":  
     cat = Categoria.objects.all().order_by("id")  
     contexto={"obj":cat}  
   if request.method=="POST":  
     ids=request.POST.getlist("ids[]")  

     cat_change = Categoria.objects.filter(pk__in=ids)  

     for item in cat_change:  

       item.estado = not item.estado  
       item.save()  

     return HttpResponse("OK")  
   return render(request,template_name,contexto)


La vista está divida en dos partes, si el método es GET, únicamente hará el filtro de todas las categorías ordenadas por id, luego pasa ese filtro a la variable contexto que luego (línea final) retorna el control a la plantilla, a la cual le pasa el contexto.

    return render(request,template_name,contexto)

La segunda parte, es cuando se invoca el método POST, en nuestro caso, mediante ajax del frontend.  en este punto, lo importante es ver cómo pide el valor de la lista

ids=request.POST.getlist("ids[]")

Si te fijas, es igual a como se envió desde el front end, pero se le indica que es una lista (getlist), importante, debe tener los dos corchetes de apertura y cierre ([])

Luego de tener la lista, lo próximo es filtrar del modelo categoría todos los objetos que en su pk tengan el id de la lista anterior, para eso utilizamos el elmento de ORM in.

Pude agregar una validación, si devolvía objetos y si no había, se lo hiciera saber al fronend por medio del return HTTResponse, pero al final no lo hice.

Ok, con todos los objetos, lo que hará es recorrer esa variable y por cada uno, irá cambiando el estado a lo contrario de lo que tenía y lo irá guardando uno por uno:

 for item in cat_change:  
       print(item.id,item.descripcion,item.estado)  
       item.estado = not item.estado  
       item.save() 

Al finalizar envía la palabra OK, por medio de HttpResponse (importante importarlo) y listo, ya tenemos toda la funcionalidad.


Sólo hará falta definir las rutas, una para mostrar la lista y la otra para trabajar el POST:
 from .views import  categoria_change_state  
 urlpatterns = [  
   path('categorias-list/',categoria_change_state, name='categoria_list_activar'),  
   path('categorias-change-state/',categoria_change_state, name='categoria_change_state'),  
 ]  

Y bueno, espero que este pequeño aporte te sea de utilidad, cualquier duda, puedes consultar acá o también puedes adquirir el curso más completo que he podido hacer sobre Desarrollo Web con Python usando Django.


 Por tiempo limitado descuento del 95%

Por tiempo limitado, 95% con este enlace http://bit.ly/lastpromo9 o puedes escribirme para saber qué promoción puedo tener, pero te garantizo que vale la pena.

Bueno, será hasta la próxima y recuerda el enlace donde encontrarás muchos cursos con descuento http://bit.ly/lastpromo9

0 comentarios:

Publicar un comentario

¿Tienes algún comentario? ¿Qué te ha parecido este artículo? Cuéntalo.

 
>