Hoy aprendí #2

Eryx - Coop&Tech
Eryx
4 min readMar 26, 2024

--

En Eryx nos gusta compartir el conocimiento y eso es lo que hacemos en Hoy Aprendí. Descubrí tips e insights claves de nuestro equipo técnico para aplicarlos en tu día a día.

Alternativas para mayor legibilidad en la manipulación de querysets de Django

Por Naza Rueda

Contexto

Una de las formas con las que tradicionalmente filtrábamos querysets para una misma clase de Django era concatenando los resultados de cada filter. Pero ¿Cómo podemos ganar mayor legibilidad a la hora de manipular querysets?

Cómo lo resolvimos

Primero y principal, abstraemos cada filter a un mensaje nuevo dándole un nombre declarativo. Luego, podemos conseguir condiciones más complejas a través de 2 formas:

  1. Concatenando los mensajes
  2. Utilizando el operador lógico AND (&)

Asumiendo que tenemos estas clases:

class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField("date published")

objects = QuestionQuerySet.as_manager()

def __str__(self):
return self.question_text

def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)


class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)

objects = ChoiceQuerySet.as_manager()

def __str__(self):
return self.choice_text

Y por otro lado que tenemos estos querysets:

class QuestionQuerySet(models.QuerySet):
def published_recently(self):
return self.filter(pub_date__gte=timezone.now() - datetime.timedelta(days=3))


class ChoiceQuerySet(models.QuerySet):
def filter_by(self, question):
return self.filter(question__question=question)

def with_votes_greater_than(self, votes):
return self.filter(votes__gt=votes)

Para el primer caso podemos ejecutar:

programming_language_question = Question.objects.get(question_text="What is your favorite programming language?")
Choice.objects.filter(question=question) & Choice.objects.filter(votes__gt=2)
def most_voted_choice_for(self, question):
return self.filter_by(question).with_votes_greater_than(10)
def most_voted_choice_for(self, question):
return self.filter_by(question) & with_votes_greater_than(10)

Creamos una pregunta para poder obtener una opción asociada a estos filtros:

programming_language_question = Question.objects.get(question_text="What is your favorite programming language?")

Estas formas de filtrado son análogas:

Choice.objects.filter(question=question) & Choice.objects.filter(votes__gt=10)
Choice.objects.filter(question=question).filter(votes__gt=10)

Encapsulando esos filtros en mensajes podemos obtener:

def most_voted_choice_for(self, question):
return self.filter_by(question).with_votes_greater_than(10)
def most_voted_choice_for(self, question):
return self.filter_by(question) & with_votes_greater_than(10)

Descifrando Redux, un framework de frontend

por Juli Arnesino

Contexto

Resolviendo un ticket para un cliente, tuvimos que entender cómo usan Redux. Les comparto lo que aprendimos.

Redux sirve para mantener un estado “global” de la aplicación y se usa en otros frameworks aparte de React. La justificación principal es ir en contra de la arquitectura clásica Model-View-Controller (MVC) de frontend, que termina con muchas interacciones complejas cuando el sistema escala. Centralizar el estado en una variable global apunta a resolverlo. Para esto implementa una arquitectura llamada Flux.

Se ejecutan Actions en el sistema (lo que en MVC sucede en la View por parte del usuario), y se mandan al Dispatcher. Este las despacha a distintas stores, que almacenan el estado de un dominio o contexto en particular. Cuando la Store recibe una Action, se la envía a un Reducer junto con el estado actual del programa, que la actualiza usando la Action recibida. Entonces el estado es sólo actualizado de esta forma. Por alguna razón, en Redux se elige la acción con una cadena de ifs medio rara.

Los componentes se suscriben a cambios en las distintas Stores elegidas y se actualizan cuando son notificados de los mismos. Un componente de este estilo es como View+Controller de MVC, o al menos los componentes que se suscriban a estos cambios. Aquellos que sólo reciban la data de otros componentes, son simplemente Views.

Flux data flow
MVC Architecture diagram

Ventajas que veo

Quita la lógica de los componentes visuales.

Si conocés el modelo del sistema, te ayuda a hacer debugging fácilmente, incluso con cosas más complejas. Esto permite debuggear siguiendo una traza de los cambios de estado global en las stores.

Desventajas que veo

Si no te comprometés completamente a la arquitectura, testear con Redux en particular puede ser un poco trabajoso.

El despacho de las Actions es raro: Redux recorre todas las Stores una por una con la acción. Cada una pasa a la Action por una sentencia switch para ver si matchea con algún tipo de acción que le interesa a ella, todo comparando strings.

Simplificando el acceso SSH a instancias EC2: automatización de cambio de IP

por Nacho Espino

Contexto

Mi proveedor de servicio de internet empezó a cambiar mi IP seguido y esto terminó generando un problema bastante tedioso en el proyecto en el que trabajo.

Para algunos procesos necesitamos conectarnos vía SSH a instancias EC2 en AWS y el mecanismo que utilizamos es configurar una inbound rule al security group asociado a la instancia que queramos acceder.

No estaba muy feliz teniendo que modificar las reglas a mano desde la consola de AWS cada vez que, por ejemplo, tenía que hacer un deploy. Ni hablar de si el deploy era un hotfix.

Cómo lo resolvimos

Seguí el consejo de un amigo: “si hiciste algo X veces a mano, deberías invertir tiempo en automatizarlo”. Así que empecé a investigar cómo poder hacer esto mismo con AWS CLI.

El resultado fue un script que permite actualizar la IP y la descripción de la regla que nosotros queramos:

aws ec2 modify-security-group-rules --region ${REGION_DE_LA_INSTANCIA} --group-id ${ID_SECURITY_GROUP} --security-group-rules  
SecurityGroupRuleId=${ID_SECURITY_GROUP_RULE_TO_CHANGE},SecurityGroupRule="{CidrIpv4=${NEW_CIDR_IP},
IpProtocol=${PROTOCOL},FromPort=${FROM_PORT},ToPort=${TO_PORT},Description=${NEW_SECURITY_GROUP_RULE_DESCRIPTION}}"

Algunas aclaraciones:

NEW_CIDR_IP lo pueden obtener de la siguiente manera:

CURRENT_IP=$(curl --silent https://checkip.amazonaws.com)
NEW_CIDR_IP="${CURRENT_IP}"/32

Valores de ejemplo:

PROTOCOL="tcp"
FROM_PORT=22
TO_PORT=22

y NEW_SECURITY_GROUP_RULE_DESCRIPTION es un string que describe la regla. Se puede utilizar para describir desde donde se está accediendo la instancia, por ejemplo: “Narnia”.

Seguinos también en Instagram y LinkedIn.

--

--