Cansada de ser feliz

Bienvenidos a mi flujo de conciencia

How to send an email with attachment via Amazon SES in Python

| Comments

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import xlwt
from boto3 import client

email_from = 'from@example.com'
email_to = 'to@example.com'

# Create a workbook
xls = xlwt.Workbook()
# Create a sheet
sheet = xls.add_sheet('Sheet name')
# Set styles for headers and dates
header_style = xlwt.easyxf('font: bold True;')
date_format = xlwt.XFStyle()
date_format.num_format_str = 'dd/mm/yyyy hh:mm:ss'

# Header
labels = [
    u'Title 1',
    u'Title 2',
]
content = [labels]

# Get data for other rows
for row in get_rows_with_content():
    content.append(list(row))

# Write it down
for row in range(len(content)):
    for col in range(len(content[row])):
        data = content[row][col]
        # If it's a header
        if row == 0:
            sheet.write(row, col, data, header_style)
            continue
        # If it's a date
        if type(data) == datetime.datetime:
            sheet.write(row, col, data, date_format)
        else:
            sheet.write(row, col, data)

# Set filename
today = datetime.date.today()
file_name = 'my_file_{}.xls'.format(today.strftime("%Y-%m-%d"))

# Save the file
output = StringIO.StringIO()
xls.save(output)

# Build an email
msg = MIMEMultipart()
msg['Subject'] = 'Hi, here is your file'
msg['From'] = email_from
msg['To'] = email_to
# What a recipient sees if they don't use an email reader
msg.preamble = 'Multipart message.\n'

# The attachment
part = MIMEApplication(output.getvalue())
part.add_header('Content-Disposition', 'attachment', filename=file_name)
part.add_header('Content-Type', 'application/vnd.ms-excel; charset=UTF-8')
msg.attach(part)

# Connect to Amazon SES
ses = client(
    'ses',
    region_name='us-east-1',
    aws_access_key_id=config['AWS_ACCESS_KEY_ID'],
    aws_secret_access_key=config['AWS_SECRET_ACCESS_KEY'],
)
# And finally, send the email
ses.send_raw_email(
    Source=email_from,
    Destinations=[email_to],
    RawMessage={
        'Data': msg.as_string(),
    }
)

If we need to create a ZIP archive first:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import zipfile
import tempfile
from email import encoders
from email.mime.multipart import MIMEMultipart, MIMEBase

# ....
output = StringIO.StringIO()
xls.save(output)

# Create zip file
zf = tempfile.TemporaryFile(prefix='fileprefix', suffix='.zip')
zip = zipfile.ZipFile(zf, 'w')
zip.writestr(file_name, output.getvalue())
zip.close()
zf.seek(0)

msg = MIMEMultipart()
msg['Subject'] = 'Hi, here is your file'
msg['From'] = email_from
msg['To'] = email_to

# What a recipient sees if they don't use an email reader
msg.preamble = 'Multipart message.\n'

# the attachment
part = MIMEBase('application', 'zip')
part.set_payload(zf.read())
encoders.encode_base64(part)
part.add_header(
    'Content-Disposition', 'attachment',
    filename=u'{}.zip'.format(file_name),
)
msg.attach(part)
# ....

Cómo pasar variable desde una vista a formulario en Django

| Comments

views.py
1
2
3
4
5
6
7
8
9
10
11
12
class MyCreateView(CreateView):
    model = MyModel
    template_name = 'myapp/my_form.html'
    form_class = MyForm

    def get_form_kwargs(self):
        kwargs = super(MyCreateView, self).get_form_kwargs()

        # La variable que queremos pasar al formulario
        kwargs.update({'current_user': self.request.user})

        return kwargs
forms.py
1
2
3
4
5
6
7
class MyForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        # Recibir la variable y borrarla del listado de argumentos.
        current_user = kwargs.pop('current_user')

        super(MyForm, self).__init__(*args, **kwargs)

Herramientas para el desarrollo que nos hacen la vida más fácil

| Comments

Editores

Plugins para Sublime Text

Para llamar Package Control desde Sublime Text: Control+Shift+P, escribe “install” y selecciona Package Control: Install Package en Command Palette.

Editar y compartir código en línea

  • CodePen: editor de código HTML/JS/CSS en línea.
  • repl.it: editor de Python 3 que permite compartir el código.
  • Dillinger: editor de Markdown.

Bases de datos

Git

Screenshots

  • Shutter: aplicación para tomar y editar screetshots en Linux.

REST

  • PostMan: es una extensión del Google Chrome, que permite el envío de peticiones HTTP.

Diff y validación

CSS/Iconos

Múltiples bases de datos en Django

| Comments

Tenemos dos tablas con esquemas iguales dos en bases de datos diferentes: production y history.

settings.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
DATABASE_ROUTERS = ['routers.HistoricRouter']

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'HOST': 'localhost',
        'NAME': 'production',
        'USER': 'secret',
        'PASSWORD': 'secret',
    },
    'historical': {
        'ENGINE': 'django.db.backends.postgresql',
        'HOST': 'localhost',
        'NAME': 'history',
        'USER': 'secret',
        'PASSWORD': 'secret',
    }
}

Escribimos un router para definir a qué base de datos hacer la petición:

routers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class HistoricRouter(object):
    """
    A router to control all database operations on models in the historic application.
    """
    def db_for_read(self, model, **hints):
        """
        Attempts to read historic models go to historical.
        """
        if model._meta.app_label == 'historic':
            return 'historical'
        return None

    def db_for_write(self, model, **hints):
        """
        Attempts to write historic models go to historical.
        """
        if model._meta.app_label == 'historic':
            return 'historical'
        return None

    def allow_relation(self, obj1, obj2, **hints):
        """
        Allow relations if a model in the historic app is involved.
        """
        if obj1._meta.app_label == 'historic' or \
            obj2._meta.app_label == 'historic':
            return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        Make sure the historic app only appears in the 'historical' database.
        """
        if app_label == 'historic':
            return db == 'historical'
        return None

En nuestros modelos especificamos app_label para referirnos a la base de datos distinta a default:

models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Author(models.Model):

    class Meta:
        db_table = 'authors'

class AbstractBook(models.Model):
    author = models.ForeignKey('books.Author', related_name='books')
    created_at = models.DateTimeField()

    class Meta:
        unmanaged = True
        abstract = True

class Book(Book):

    class Meta:
        db_table = 'books'

class HistoricBook(Book):

    class Meta:
        unmanaged = True
        db_table = 'books'
        app_label = 'historic'

La petición Book.objects.all() va a traer libros de la base de datos production y HistoricBook.objects.all() - de la base de datos history.

Modificando allow_relation en nuestro router, podemos permitir llaves foráneas entre modelos de diferentes bases de datos:

1
2
def allow_relation(self, obj1, obj2, **hints):
    return True

Enlaces:

Cómo hacer integración con Tpaga API usando Python

| Comments

Tpaga es una plataforma que permite recibir pagos electrónicos. Tiene una estructura sencilla para entender y fácil para usar.

Para obtener nuestros claves de acceso y conectarnos con el API de Tpaga, creamos una cuenta en el “sandbox” de la plataforma: sandbox.tpaga.co.

Al registrarnos podemos ver que ahora tenemos dos claves que podemos usar para la autenticación: Private Api Key y Public Api Key:

No llevas leña

| Comments

El bus lleno de Buratinos* va a toda velocidad. En algún momento el conductor frena duro, y escucha las voces enojadas del los pasajeros: “¡Ey, señor conductor, no lleva la leña!”

*Buratino es Pinocchio en ruso.

El colegio

| Comments

Nunca me gustaba ir al colegio y siempre he contado cuánto falta hasta el último día de encarcelamiento.

Entré al colegio cuando tenía 7 años. Normalmente los niños entran un año antes, pero a mis 6 me dijeron que la niña era demasiado pequeña. Durante 12 meses no crecí mucho, pero ya que no tuvieron razones de no aceptarme.

Mi primer día no me gustó: habían muchos niños a quienes no conocía y no quería conocerlos, que se movían por el salón de una forma caótica y hacían mucho ruido. Me pusieron en la última mesa del aula junto a la ventana. En la primera clase a profesora nos dijo que sacaramos nuestros cuadernos de las maletas y dibujaramos algo. Eso fue un estrés total: no pude abrir mi maleta. Como tuve que manejar la cerradura por primera vez en mi vida, no supe cómo funcionaba y claro que el panico, que llegó inmediatamente, no me permitió pensar con claridad.

Del primer grado sólo recuerdo cómo nos enseñaban caligrafía: tuvimos que escribir las mismas letras muchas veces. Entonces al final se quedaron varias páginas con “а”, “б”, “в”, etc.

En el segundo grado nos muvieron a otro edificio y empezamos a prestar servicio. Cada grupo por turnos tuvo que estar de servicio en el colegio durante toda la semana. Esto segnificaba que tuvimos que llegar 30 minutos antes que todos los demás. Nos reunían en el primer piso y decían a cada no su cargo. Habían varios tipos de cargos: unos tuvieron que estar en la entrada del edificio y en las entradas de cada piso y decir a cada niño que pasaba: “¡Smenka!”. “Smenka” significa “los zapatos de cambio”. En el invierno la nieve se metía en las indiduras de los zapatos y cuando uno entraba al edificio se derretía y dejaba charcos. Por eso por el orden “¡Smenka!” el estudiante tuvo que levantar el pie y mostrar la suela. Si estaba mojada “el guardia” tuvo que detenerlo y mandarlo a la casa por los zapatos de cambio. Ese cargo no me gustaba porque los otros estudiantes lo tomaban como un deporte lograr pasar con los zapatos que llevaban puestos en la calle, entonces inventaban trucos para confundir la guardia o simplemente corrían de nosotros. Entonces había otro cargo: vigilar los corredores, detener los estudiantes que corrían y mandarles al director del colegio.

Existía un cargo que era el más agradable de todos: estar en la cafetería. Había que ordenar las mesas y las sillas y antes de las horas del desayuno y almuerzo había que servir la comida y después recoger los platos.

Después de las clases nos quedábamos por una hora para limpiar todo el colegio.

Tuvimos 4 periodos y 4 vacaciones: 3 cortas y umas largas de tres meses en verano. Para las vacaciones de verano nos daban una lista de libros para leer. Como durante los estudios casi no tuvimos tiempo para la lectura, tuvimos que pasar por todos los libros del curso de literatura antrs de que empezara el año escolar. A pesar de que leía de 3 a 5 horas al día no alcanzaba leer todos los libros del listado. Me gusta leer mucho, pero odiaba las clases de literatura. La parte más tonta era memorizar los poemas. Tuvimos que recitar de memoria los poemas de Homero, Pushkin, Lermontov, Tiútchev, Mayakovski, Blok y muchos otros. A cada uno llamaban a la pizarra y tuvimos que declamar frente al grupo. Así los profesores lograron que hasta la mejor poesía pudiera provocar un reflejo vomitivo. Pero creo que era la mejor forma de instalar los pensamientos de otras personas a las mentes inmaduras. Hasta ahora cuando veo una tormenta fuerte a veces se me ocurren las estrofas de Tiútchev:

Люблю грозу в начале мая (Me gustan las tormentas a principios de mayo) / Когда весенний первый гром (Cuando el primer trueno primaveral) / Как бы резвяся и играя (Como haciendo travesuras y jugando) / Грохочет в небе голубом (Trona en el cielo azul).