Optimiza tu CLI en Python con un flujo de actualización claro, seguro y amigable. Aprenderás a integrar Click, un ClientService, una búsqueda por UID con list comprehension y un flow de prompts con valores por defecto para editar campos sin perder datos.
¿Cómo actualizar clientes con Click y ClientService?
Para iniciar el flujo de actualización, se crea una instancia de ClientService con el nombre de la tabla de clientes y se lista la información disponible. Luego, se localiza el registro por UID usando un list comprehension. Si no se encuentra, se notifica con click.echo. Si existe, se dispara el flow de actualización y se guarda el cambio con el servicio.
¿Cómo obtener la referencia a ClientService?
Instanciar el servicio con el nombre de la tabla de clientes.
Mantener una sola responsabilidad: el servicio maneja lectura y actualización.
¿Cómo localizar el cliente por UID con list comprehension?
Filtrar por coincidencia exacta de UID.
Asegurar match único: se valida por identificador.
client =[c for c in client_list if c['uid']== client_uid]ifnot client: click.echo('Client not found')returncliente_actualizado = update_client_flow(client[0])client_service.update_client(cliente_actualizado)click.echo('Client updated')
¿Qué mensajes y flujos se manejan con click.echo?
Cuando no hay coincidencia: client not found.
Cuando se actualiza correctamente: client updated.
Mensajes claros y breves para guiar la interacción.
¿Qué es update_client_flow y cómo usar click.prompt?
El flow de actualización guía al usuario campo por campo. Se muestra una instrucción inicial: Leave empty if you don't want to modify the value. Déjalo vacío si no quieres modificar el valor. Cada prompt usa el valor actual como default, de modo que si se presiona Enter sin escribir nada, el dato no cambia.
defupdate_client_flow(client): click.echo('Leave empty if you don\'t want to modify the value. ' \
'Déjalo vacío si no quieres modificar el valor.') name = click.prompt('New name',type=str, default=client['name']) company = click.prompt('New company',type=str, default=client['company']) email = click.prompt('New email',type=str, default=client['email']) position = click.prompt('New position',type=str, default=client['position']) client['name']= name
client['company']= company
client['email']= email
client['position']= position
return client
¿Cómo mantener valores con default en click.prompt?
Usar el dato actual del cliente como default.
Presionar Enter conserva el valor sin cambios.
Minimiza errores y acelera la edición.
¿Qué campos se actualizan en el cliente?
Nombre del cliente: name.
Compañía: company.
Correo: email.
Puesto: position.
¿Cómo se prueba el comando pv clients update?
Primero, lista los registros para identificar el UID. Luego, ejecuta el comando de actualización y responde a los prompts. Ejemplo: renombrar a Ricardo, cambiar la compañía a Tom Inc, actualizar el correo y mantener el puesto como CEO.
pv clients list
pv clients update <ID># Prompts de ejemplo:# New name: Ricardo# New company: Tom Inc# New email: ricardo@ricardo# New position: CEO
Claves prácticas:
Búsqueda por UID con list comprehension para precisión.
Mensajes de estado con click.echo para una UX clara.
Prompts con default mediante click.prompt para ediciones seguras.
Como siguiente paso, implementa la funcionalidad de delete como reto personal. ¿Cómo diseñarías el flujo y las confirmaciones? Comparte tu solución y aprendizajes en los comentarios.
en la parte que platzi recorta videos sin escrupulos. para ahorrar dinero. y entregarnos cursos de baja calidad
¡Hola @kmiiloberrio02! A veces pueden pasarse algunos errores de edición, recuerda que una característica que te ofrece Platzi es presentarte las clases de la manera más corta posible, para que puedas aprovechar al 100% tu tiempo y eliminar los momentos muertos. Agradecemos tu feedback, siempre intentamos mejorar los cursos, en la próxima actualización hallarás más calidad ;)
El **feedback ** es bueno para la plataforma, hasta ahora he visto pocas quejas de estas últimas clases, y las pocas quejas solo reciben un “disculpa, para la próxima lo arreglamos”, creo que seria mejor que los moderadores o personal de apoyo pusiera una nota al pie del video explicando los errores de la clase ( claro que no son atribuibles al profe, que dicho sea de paso es excelente). en fin es mi humilde opinión.
Completamente de acuerdo, una solución super sencilla y funcional. En otras plataformas reeditan el video, o pausan el video y colocan la nota con la errata en el segundo donde ocurre el error, o lo muestran al final del video... Aquí sólo pedimos que lo pongan abajito de la descripción... Ojalá hagan caso.
Mal, a partir del video 39 esto se fue para abajo, parese que estan correteando a David
Mi solución al reto
@clients.command()@click.argument('client_uid', type=str)@click.pass_contextdef delete(ctx, client_uid):""" Delete a client """ client_service =ClientService(ctx.obj['clients_table']) client_list = client_service.list_clients() client =[client for client in client_list if client['uid']== client_uid]ifclient: client_service.delete_client(client) click.echo('Cliente deleted')else: click.echo('Client not found')
AttributeError:'str' object has no attribute '__name__'
Lo encontré en los decoradores de la función update:
@click.argument('client_uid', type = str)
El type lo había puesto entre comillas simples y por eso salía el error. Sin embargo la consola no me mostraba en cuál archivo y cuál linea era la del problema y por eso mirando su código compartido lo pude solucionar.
Jajajajajaja se mancharon, cómo carajos vamos a poder resolver el reto de la función eliminar si no nos han explicado nada acerca de la librería click?? Aunque hayamos realizado los cursos anteriores de la ruta, a esta altura del curso no sabemos qué estamos escribiendo, solo hacemos que funcione
No me gusta decir estas cosas, pero casualmente los cursos que menos me han gustado son los de el profesor David Aroesti, siempre quedo con demasiadas dudas en sus cursos!!
Entiendo el sentiemiento que tienes pero recuerda que siempre puedes volver a las clases anteriores y repetirlas cuantas veces sea posible para entender o realizar preguntas de seguro te ayudaran con ello, saludos!
Esta es mi solución de delete:
La función delete en es casi igual a update y no utilice nada en
@clients.command()@click.pass_contextdef delete(ctx):"""Deletes a client""" client_uid = click.prompt('Client UID to delet', type=str) client_service =ClientService(ctx.obj['clients_table']) clients_list = client_service.list_clients() client =[client for client in clients_list if client['uid']!= client_uid] client_service._save_to_disk(client)```
commands
@clients.command()@click.argument('client_uid', type=str)@click.pass_contextdefdelete(ctx, client_uid):"""delete a client""" client_service =ClientService(ctx.obj['clients_table']) clients_list = client_service.list_clients() client =[client for client in clients_list if client['uid']!= client_uid]ifclient: client_service._save_to_disk(client) click.echo('Client removed')else: click.echo('Client not found')
En el de services no modifique nada, solo reutilize la funcion _save_to_disk, en el de commands, modifique en el comprehension la condicion (==) y la remplaze por (!=), la logica usada fue: agregar a la lista todos los clientes simpre y cundo no sea el uid sea indistinto al uid del cliente ingresado.
de esta manera guarda todos menos el que deseamos eliminar, esa es una alternativa
Definitivamente estas ultimas clases han estado de busca el error de edición :/
¡Hola Claudio! ¿Donde notaste el error de edición?
El código del instructor no me funcionó. Recibía este error:
_TypeError: save_to_disk() takes 1 positional argument but 2 were given
Se resuelve muy fácil agregado al método _ save_to_disk _ su "seft".
Resulto esto, recibía este error:
FileNotFoundError: [Errno 2] No such file or directory: '.clients.csv.tmp'
También se resolvía muy sencillo agregando _ _save_to_disk _ en open el argumento mode="w".
Con esto funcionó perfecto. Lo que no entiendo es por qué le funcionó al instructor. Pienso que es un error de edición en el video. Un novato se pude frustrar muy fácilmente con un error como este. Todo lo deben solucionar.
Redefiniste updated_client como una lista vacía en el inicio del for, las listas no tienen propiedades
Yo tengo el mismo error Ibrahin... Cómo podríamos resolverlo @rodriguezjp97? el código está tal cual como lo indicó el profesor en la lecció Nro. 43.
Gracias de antemano.
Hola! Les dejo el código de mi implementación para lo que vimos en el curso, lo hice en español y agregué un sistema de inventario en el que se pueden crear, actualizar, borrar, leer y vender productos. Todos los PR o forks son bienvenidos. Saludos, compañeros:)
En la clase anterior a David se le olvido colocar el modo en el que abria el archivo, deben corrergirlo.
funcion _save_to_disk de services.py
en vez de:
withopen(tmp_table_name)asf:
Escriban lo siguiente:
withopen(tmp_table_name, mode ='w')asf:
¿Qué significa el doble * en la siguiente linea?
client =_update_client_flow(Client(**client[0]))
que arrastra todo lo de cliente aqui cliente es un diccionario que esta en la posicio 0 de una lista, todos los datos del diccionario cliente los recibe con esa notacion lo arrastra a updateclientflow
Tenía la misma duda. gracias.
Por aquí les dejo mi solución al reto de implementación del módulo delete.
@clients.command()@click.argument('client_uid', type=str)@click.pass_contextdef delete(ctx, client_uid):"""Deletes a client""" client_service =ClientService(ctx.obj['clients_table']) client_list = client_service.list_clients() client =[client for client in client_list if client['uid']==client_uid]ifclient: client_service.delete_client(client_uid) click.echo('Client deleted!!')else: click.echo('Client not found!!')
def delete_client(self, client_uid): clients = self.list_clients() updated_clients =[client for client in clients if client_uid!=client['uid']] self._save_to_disk(updated_clients)
Hola!, me sale el siguiente error =
TypeError: update() missing 1 required positional argument: 'client_uid'
este es mi update de commands.py
def update(ctx, client_uid):"""Updates a client""" client_service =ClientService(ctx.onj['clients_table']) client_list = client_service.list_clients client =[client for client in client_list if client['uid']== client_uid]ifclient: client =_update_client_flow(Client(**client[0])) client_service.update_client(client) click.echo('Client updated')else: click.echo('Client not found')
Esto se debe que como ves en tu codigo no hay ninguna variable con cliente_uid ademas tambien no estas pidiendo en algun momento generar algun client_uid
Cierto, a mi también me falto declarar la variable ++client_uid++ .
Gracias por el apoyo! :D
Todo me corre perfectamente. Pero cuando actualizo un cliente no se me cambia en el .clients.csv. Incluso me sale el echo de "Client updated", pero cuando hago pv list me sale el cliente anterior. Cuando no me sale un error es más dificil saber que esta pasando...
Compara las uuid(en el update_client del service.py) a ver si coinciden. Si no coinciden el condicional no te esta funcionando.
Recuerda que debes tener esta linea en tu models.py:
self.uid = uid or uuid.uuid4()
Ayuda... en el minuto 3:02, ¿A que se refiere a desempaquetar? ¿Qué significa el doble asterisco [**]? (es alguna clase de apuntador?)
Gracias <3