Índice de contenido
Es momento de otra práctica para ampliar nuestras capacidades mediante la Inteligencia Artificial. En esta ocasión, utilizaremos Google Antigravity, una versión modificada de VS Code diseñada para potenciar el flujo de trabajo con agentes inteligentes.
Si quieres seguir esta práctica, puedes descargar la herramienta directamente desde su página oficial. La diferencia fundamental con el editor tradicional es que incluye una pestaña de Agente y una herramienta de Planificación, que es lo que exploraremos hoy.
Considero que la forma actual de programar implica emplear una IA. Si no la usas, tu competencia sí lo hará y perderás terreno. En este curso, equilibramos la enseñanza tradicional con estas herramientas para agilizar desarrollos que ya cubrimos previamente, como la creación de listados y detalles.
El Proyecto: Módulo de Blog con Django
Para esta práctica, le pedí a la IA que desarrollara un módulo de Blog que nos faltaba. El objetivo era crear:
- Listado de posts: Con filtros por categorías, tipos y paginación.
- Página de detalle: Maquetada con Bootstrap.
- Modelos existentes: En lugar de crear un modelo nuevo desde cero, le instruí para que utilizara nuestro modelo elementos (que simula los posts) y sus relaciones con categoría y tipo.
Este es el prompt:
Crea un modulo en la app de elements para tener un Blog con Filtros por tipos, categoría, paginado y maquetado con Bootstrap, que tenga el listado y el detalle.
Es un prompt bastante mejorable ya que, NO especificamos aspectos sobre si queremos que cree un modelo (en nuestro caso queremos que emplee la relación de Elementos):
class Category(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(max_length=255,blank=True)
def __str__(self):
return self.title
class Type(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(max_length=255,blank=True)
def __str__(self):
return self.title
class ElementManager(models.Manager):
def get_queryset(self):
# Siempre que usemos Element.objects.all(), incluirá el select_related
return super().get_queryset().select_related('category', 'type')
class Element(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(max_length=255,blank=True)
description = models.TextField() # blank=True, null=True
price = models.DecimalField(max_digits=10,decimal_places=2, default=6.10) # 12345678.10
category = models.ForeignKey(Category, on_delete=models.CASCADE) #, related_name='elements'
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
type = models.ForeignKey(Type, on_delete=models.CASCADE)No le damos capturas de pantalla sobre como queremos que luzca el desarrollo entre otros aspectos que quisieras agregar. Aunque, si le indicamos cual es la app que tiene que inspeccionar (la de elements) esto nos ahorrará algunos tokens y tiempo cuando Google Antigravity empiece a evaluar el proyecto.
Aun así, con esto esto, podemos interactuar con la herramienta y conocer como funciona.
La Herramienta de Planificación (Planning Tool)
Esta es la principal ventaja de Antigravity frente a otras herramientas como Gemini CLI o Agent. Antes de ejecutar cualquier código, el agente genera una Hoja de Ruta (Roadmap).
La IA te dice exactamente qué archivos va a modificar o crear:

Figura 18-4: Hoja de Ruta generada por Google Antigravity
Como puedes apreciar en la Hoja de Ruta, la IA quiere generar un nuevo modelo, que no es lo que queremos (y esto es debido a que le dimos un mal prompt), pero, tenemos la oportunidad de corregir e indicarle que “No cree un nuevo modelo, que use el de Element en su lugar”
Si la IA intenta crear un modelo llamado Post y tú quieres que use Elementos, puedes agregar un comentario en la planificación. Ella reajustará su plan antes de tocar una sola línea de código.
Como recomendación de seguridad, siempre sincroniza tu proyecto con Git antes de aceptar los cambios. Si el resultado no es el esperado, puedes volver atrás fácilmente con un git reset --hard HEAD.
Adicionalmente, el editor en una oportunidad se quedo “Pensando…” indeterminadamente, ya que, tuvo un error al intentar levantar el ambiente virtual y ejecutar el comando para generar las migraciones:
python manage.py makemigrations
zsh: command not found: pythonfrom django.core.management import execute_from_command_line
ModuleNotFoundError: No module named 'django'ImportError: Couldn't import Django. Are you sure it's installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment?
Ejecuté el comando de manera manual y le indiqué al Agente IA que ejecuté el comando por el, pero, el Agente aun no respondida, así que, tuve que terminar su ejecución y volver a iniciarlo para indicarle que siga con la ejecución de generar las vistas y templates (que era la siguiente tarea a realizar).
Implementación y Resultados
Tras algunas iteraciones en lo cual, debes de hacer lo mismo que hicimos antes, ver la Hoja de Ruta y si uno de los desarrollos que plantea la IA no corresponde con lo que quieres hacer, agregas un comentario y click sobre el botón “Proceed” que aparece en la esquina superior derecha hasta tener la Hoja de Ruta clara para tu aplicación.
Al final, la IA generó una maqueta funcional basada en tarjetas (cards) de Bootstrap con los filtros para categorías y listados y una página de detalle:

Figura 18-5: Diseño obtenido
Características del desarrollo generado
Filtros dinámicos: La vista verifica de forma opcional si existe un parámetro de categoría o tipo en la URL y ajusta la consulta inicial:
elements\views.py
def blog_list(request):
elements = Element.objects.select_related('category', 'type').all()
# Filters
type_slug = request.GET.get('type')
category_slug = request.GET.get('category')
if type_slug:
elements = elements.filter(type__slug=type_slug)
if category_slug:
elements = elements.filter(category__slug=category_slug)Optimización de consultas: Utilizó select_related para traer las relaciones de categorías y tipos, evitando el problema de las consultas N+1 (un error común que ralentiza las aplicaciones):
elements = Element.objects.select_related('category', 'type').all()elements\views.py
Manejo de Slugs: Configuró las rutas para utilizar el campo slug en lugar de la id (PK), lo cual es mucho mejor para el SEO:
elements\urls.py
path('blog/<slug:slug>/', blog_detail, name='blog_detail'),elements\views.py
def blog_detail(request, slug):
element = get_object_or_404(Element, slug=slug)
return render(request, 'elements/blog_detail.html', {'element': element})Paginación: Implementó la lógica para leer el parámetro de página y pasar los objetos correspondientes al template.
Conclusiones
Como podemos apreciar, este tipo de herramientas nos da muchas ventajas en el desarrollo moderno, aunque posiblemente si haces una interacción similar a la mostrada en este apartado no tendrás un resultado igual a este, por ejemplo, esta prueba la hice dos veces en el mismo proyecto base y en la primera interacción tuve que hacer correcciones adicionales como indicar de que utilice el slug en vez de la tabla PK, ademas de que, completé el desarrollo, indicándole en un segundo prompt, que, dado unas imágenes de referencias para el listado y detalles, aplique un diseño similar y que, también use una tipografía similar:
elements\templates\base.html
<!-- Google Fonts -->
<link
href="https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,700;1,400;1,700&family=Open+Sans:ital,wght@0,300;0,400;0,600;0,700;0,800;1,300;1,400;1,600;1,700;1,800&display=swap"
rel="stylesheet">
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="{% static 'css/styles.css' %}">
<style>
body {
font-family: 'Lora', 'Times New Roman', serif;
font-size: 20px;
color: #212529;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-weight: 800;
}
</style> En resumen, aunque la IA puede inferir el diseño a partir de capturas de pantalla que le adjuntes, siempre es necesario realizar ajustes manuales. Por ejemplo, en esta práctica tuvimos que corregir pequeños errores de sintaxis en los templates (como etiquetas mal cerradas). Y recordar que estas son solo herramientas y que NO sustituyen a un programador.