Diferencias entre default, null y blank en Django

En este articulo explico las diferencias entre default, null y blank en Django.

Los tipos de campo que emplea Django puedes revisarlos en la explicación de los campos en los modelos en su pagina oficial.

Nul

El campo nulo (Null) cuando posee valor TRUE, permitirá  guardar  valores vacíos como NULL en la base de datos. Su valor por defecto  es False.

Dicho esto, las cadenas vacías siempre se guardarán como cadenas vacías, no como NULL.

Por tanto, lo adecuado es usarlo   para campos que no sean cadenas (fechas, enteros, o booleanos.

Blank

El campo blank cuando es TRUE,  puede dejarse en blanco y por  defecto su valor es False.

Blank se diferencia de Null, porque Blank se emplea en validaciones, mientras Null se emplea en la base de datos.

Si un campo blank es True, la validación en el sitio de Django  permitirá que se añada un campo vacío, sino es asi por el contrario, y  blank=False, el campo será requerido.

Por tanto, considerando lo explicado anteriormente al hablar de Null,  si tenemos datos del tipo booleano, date o entero,  y lo hemos declarado null, es entonces  obligatorio también definirlos como  blank=True .

Ya que esto permitirá si valores vacíos en los formularios

logo django
django

Default

El valor por defecto (default) de un campo, ha de ser llamable  y por tanto si es llamable, se llamará cada vez que un objeto nuevo sea creado.

Resumiendo el concepto del uso de estos seria:

  • Usa «default» para definir el valor que se dará a un campo si tu código no lo define.
  • Usa «blank» para validaciones de formulario. blank=True permite que el campo se deje en blanco.
  • Usa «null» si quieres guardar valores vacíos como NULL en la base de datos.

Espero humildemente, que esto sirva de ayuda a alguien.

«El elefante no necesita decir cuan alto es, le basta con caminar»

NS

Error: Provide a one-off default now

django error

Si en alguna ocasión al trabajar con Django, y correr una migración recibes el error Provide a one-off default now, entonces este post puede serte de ayuda.

Este error, suele suceder cuando añadimos a un modelo ya existente, una nueva llave (ForeingKey), con un valor determinado.

En este post mostraré dos formas de hacerlo.

Siguiendo la documentación, Añadir una ForeignKey (non-nullable) en Django se divide en tres pasos:

Veamos primero la situación inicial:

class Post(models.Model):
    name = models.CharField(max_length=100)

Paso 1.

Primero se añade la nueva llave, donde primero definiremos null, como null=TRUE y luego desde consola correremos makemigrations().

Esto creará una nueva migración que añade el campo que hemos creado.a la tabla, por tanto ahora tenemos una nueva columna con todas sus filas con valor Null.

class Post(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, null=True, on_delete=models.CASCADE))

$ python manage.py makemigrations
Migrations for 'mi_App':
  mi_App/migrations/0002_post_category.py
    - Add field author to post

Paso 2

Ahora correremos nuevamente makemigrations, creando una una nueva migración vacía  (makemigrations --empty).

$ python manage.py makemigrations  --empty -n mi_App assign_category
Migrations for 'mi_App':
 mi_App/migrations/0003_assign_category.py

Ahora  editamos esta migración para que contenga los datos que deseamos, y es en este momento donde de acuerdo a nuestra necesidades colocaremos el valor que debe tener la nueva Foreign key.

from django.db import migrations

def assign_category(apps, schema_editor):
    Category= apps.get_model('category', 'Category')  
    Post = apps.get_model('mi_App', 'Post')               
    
    Post.objects.all().update(category=category)  # and bulk update all posts.


class Migration(migrations.Migration):

    dependencies = [...]

    operations = [
        migrations.RunPython(assign_category, migrations.RunPython.noop),
    ]

Otros posts sobre Django

Paso 3

En el tercer paso modificaremos la nueva ForeignKey en nuestro modelo, eliminando la posibilidad de valor nulo:

null=False 

class Post(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, null=False, on_delete=models.CASCADE))

Y creamos una nueva migración corriendo nuevamente makemigrations.

$ python manage.py makemigrations mi_App -n post_category_non_null

Recibirás este mensaje:

You are trying to change the nullable field 'author' on something. to non-nullable without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Ignore for now, and let me handle existing rows with NULL myself (e.g. because you added a RunPython or RunSQL operation to handle NULL values in a previous data migration)
 3) Quit, and let me add a default in models.py

Seleccionamos la opción 2 y problema resuelto.

Migrations for 'mi_App':
  something/migrations/0004_post_author_non_null.py
    - Alter field category on post

Este es el camino más largo, que sugiere la documentación, pero como siempre hay una posibilidad mas corta:

  1. En la carpeta migraciones eliminamos todas la migraciones existentes,
  2. corremos nuevamente makemigrations, con las modificaciones nuevas.
  3. corremos migrate
  4. creamos nuevamente el superusuario

Con esto quedaría resuelto.

Espero sinceramente, que esto sirva de ayuda a alguien .

……..y para cuando a ti te estén rompiendo el alma, ya el tiempo habrá cicatrizado mis heridas.

A. Torres

Un saludo

AttributeError: _io.TextIOWrapper object has no attribute  split

error en python

El error  _io.TextIOWrapper object has no attribute  split, que nos puede aparecer en Python, en alguna ocasión, suele tener una explicación sencilla.

Tal y como nos dice el propio error, el objeto no posee un atributo o método split().

Según mi experiencia, lo que sucede es que este error común cuando comenzamos , se debe a que estamos confundiendo un tipo de objeto (file), con un tipo de dato(string).

‘El objeto io.TextIOWrapper‘, es el que se obtiene cuando abrimos un documento con open() y este no ha sido leído, ni se ha escrito sobre el.  

El atributo, función o método split() corresponde a objetos de tipo string o cadenas, mientras que los objetos de tipo file, aun cuando  pueden tener un contenido de tipo texto, no son compatibles con split().

Por tanto, es a los string a los que podemos aplicarle  split(), para separar según el elemento que digamos, sus partes.

a= 'serio.jose.alberto.123.124.126' b = a.split('.') print (b)
1
a= 'serio.jose.alberto.123.124.126'
2
b = a.split('.')
3
print (b)
output:
['serio', 'jose', 'alberto', '123', '124', '126']

Hay muchas formas de dividir un objeto tipo file en partes o fragmentos.

Aquí, veremos algunos ejemplos:

Dividiendo un objeto tipo file en líneas

with open('mi_file.txt') as file:  #el metodo open ()pertenece al objeto 
                                   # file, por tanto open
                                   # siempre retorna un objeto tipo file
    mi_file = [line.rstrip('\n') for line in file]

Dividiendo segun otros elementos

Una solución que te permitirá, obtener tu objetivo, por otra vía, es convertir tu objeto file a un objeto string mediante el método read(), y luego aplicarle a este  el método split()

Veámoslo:

with open('/Volumes/Searc/testing/texto.txt','r') as file: #abrimos el objeto file 
    mi_file=file.read()  #lo leemos
    mi_div = mi_file.split(',') # le aplicamos el método split()
    print(mi_div)

La salida seria una lista con el texto dividido según comas.

output:

['Lorem ipsum dolor sit amet', ' consectetur adipiscing elit.\nCurabitur aliquet sem eget magna fermentum', ' non aliquam tortor volutpat.\nNunc pulvinar', ' dolor nec porttitor iaculis', ' diam elit finibus purus', ' et finibus ligula diam luctus erat.\nMorbi placerat sodales ligula. Aliquam iaculis congue libero', ' vel consequat tellus ullamcorper nec.\nPhasellus venenatis tempus pulvinar. Nunc nec fringilla elit. In dignissim nulla eget ligula facilisis cursus.\nVestibulum malesuada nunc sit amet turpis cursus rhoncus sollicitudin quis nisi. Sed pharetra augue nec hendrerit imperdiet.\nVestibulum volutpat dignissim nisl', ' a lobortis lacus hendrerit ut. Suspendisse ac orci felis.\nEtiam arcu tortor', ' lobortis eget commodo in', ' luctus vitae quam.\nDuis convallis', ' metus et luctus convallis', ' metus elit accumsan arcu', ' ac pretium magna justo nec ligula.\nNullam lectus arcu', ' elementum in consectetur id', ' tincidunt id justo.\nCurabitur urna nisl', ' faucibus eget ullamcorper tincidunt', ' tincidunt non ligula.\nCras mi quam', ' venenatis non suscipit vitae', ' fringilla ut tortor. Sed pellentesque turpis quis tincidunt finibus.\nNam eget volutpat metus. Duis viverra', ' mi eget egestas porta', ' purus ligula placerat nunc', ' eu finibus arcu mi eu magna.\nDonec porta lacus ut erat suscipit', ' at tincidunt mi eleifend. Quisque auctor condimentum purus', ' sit amet tempor turpis luctus ac.\nCurabitur placerat tincidunt eros ac lacinia. Curabitur malesuada hendrerit pharetra. Quisque elit ante', ' egestas quis porttitor quis', ' lacinia eu lectus. Donec dictum dictum mattis.']

Python nos permite leer el contenido de un archivo, con read.

El método read, acepta un parámetro o argumento opcional size, para leer l cierta cantidad de datos y devolverlos como una cadena (en modo de texto) o un objeto de bytes (en modo binario).

Si omites el tamaño o es negativo, Python leerá y devolverá todo el contenido del archivo; esto con archivos muy grandes puede afectar la memoria.

Read devuelve una cadena vacia si lleg al final del archivo y no puede leerlo.

Puedes ver lo métodos del objeto file aquí

Y hasta aquí, espero sinceramente que esto sirva de ayuda a alguien.

El viento hincha la vela, pero la deshilacha y hay tantas velas rotas en el fondo del mar.

J. A. Buesa

TypeError: module.__init__() takes at most 2 arguments (3 given)

python error

TypeError: module.__init__() takes at most 2 arguments (3 given), como su nombre indica, es un error de tipo, que generalmente hace referencia a la estructura que empleamos al importar nuestro módulos, para construir objetos en Python.

La estructura correcta al importar debería seguir esta lógica.

from Object
import ClassName

Para definir la clase podría ser

class Visitor(Object.ClassName):

Podemos también hacer esto:

from Object
import Object as Parent

Y en la definición de la clase llamar directamente a parent

class Visitor(Parent):

Errores en Python

Una estructura adecuada incluso, puede extenderse a diferentes módulos en algo como esto:

from zonas
import NomenclaturaZonas

Si deseáramos emplearlo en otro modulo podría ser: 

from zonas.NomenclaturaZonas
import NomenclaturaZonas

Si nuestro archivo es Parent1 y el classname Parent, podemos escribirlo de esta forma: 

from Parent1
import Parent

Sin embargo, si Parent1.py esta dentro de una carpeta con esta ruta

DemoFolder - > Parent1.py - > Parent(Folder).(File).(Class name)

La forma de acceder seríaa.

from Test.Parent1
import Parent

Y hasta aquí, espero que sinceramente ayudar a alguien con este post.

Subir montañas, hermana hombres

J.Martí

NameError en Python

python error

El error  NameError en Python   ocurre cuando el intérprete CPython no reconoce un nombre de objeto local o global que se haya proporcionado en el código fuente de Python.

Este error hereda de Exception que a su vez se extiende  BaseException

BaseException  -> Exception -> NameError

Emplearemos este código de ejemplo:

import dis


from gw_utility.logging import Logging


def main():
    try:
        # Create Auto.
        auto = Auto("Chevrolet, "Bell Air", 50, datetime.date(1956))

        # Log auto object.
        Logging.line_separator("log_object(auto)", 60)
        log_object(auto)

        # Log invalid object.
        Logging.line_separator("log_invalid_object(auto)", 60)
        log_invalid_object(auto)

        # Disassemble both log_ functions.
        Logging.line_separator("DISASSEMBLY OF log_object()", 60)
        disassemble_object(log_object)

        Logging.line_separator("DISASSEMBLY OF log_invalid_object()", 60)
        disassemble_object(log_invalid_object)
    except NameError as error:
        # Salida esperada es NameErrors.
        Logging.log_exception(error)
    except Exception as exception:
        # Salida inesperada es una Excepcion.
        Logging.log_exception(exception, False)


def log_object(value):
    """Registro del valor de parametro pasado a consola.

    :param value: Value to be logged.
    :return: None
    """
    try:
        Logging.log(value)
    except NameError as error:
        # Salida esperada es NameErrors
        Logging.log_exception(error)
    except Exception as exception:
        # Salida inesperada es una Excepcion.
        Logging.log_exception(exception, False)


def log_invalid_object(value):
    """Intenta  registrar el objeto invalido  valu en la consola

    :param value: Value intended to be logged, but which is instead ignored.
    :return: None
    """
    try:
        Logging.log(valu)
    except NameError as error:
        # Salida esperada es NameErrors
        Logging.log_exception(error)
    except Exception as exception:
        # Salida inesperada es una Excepcion.
        Logging.log_exception(exception, False)


def disassemble_object(value):
    """salida desensamblada del objeto pasado.

    :param value: Object to be disassembled.
    :return: None
    """
    dis.dis(value)


if __name__ == "__main__":
    main()

# auto.py
import datetime


class Auto:
    marca: str
    modelo: int
    potencia: str
    año de fabricación: datetime.date
    potencia: str

    def __eq__(self, other):
        """Determina si el objeto pasado, es equivalente al objeto actual"""
        return self.__dict__ == other.__dict__

    def __init__(self,
                 marca: str = None,
                 modelo: str = None,
                 potencia: int = None,
                 año_fabricacion: datetime.date = None):
        """Inicializa una instanci de Auto .

        :param marca: Nombre de la marca.
        :param modelo: Modelo.
        :param potencia: Potencia en HP.
        :param año_fabricacion: Año de fabricación.
        """
        self.marca = marca
        self.modelo = modelo
        self.potencia = potencia
        self.año_fabricacion = año_fabricacion

    def __getattr__(self, marca: str):
        """Devuelve el atributo pasado comparandolo con marca."""
        # Get internal dict value matching marca.
        value = self.__dict__.get(marca)
        if not value:
            # Lanza AttributeError si el atributo no se encuentra.
            raise AttributeError(f'{self.__class__.__marca__}.{marca} is invalid.')
        # Devuelve el valor del atributo
        return value

    def __len__(self):
        """Devuelve la longitud de la marca."""
        return len(self.title)

    def __str__(self):
        """Retorna una cadena formateada que representa a SAuto."""
        año_fabricacion = '' if self.año_fabricacion is None else f', fabricado en {self.año_fabricacion.__format__(" %Y")}'
        potencia = '' if self.potencia is None else f' con {self.potencia}  de fuerza'
        return f'\'{self.modelo}\'  de la marca {self.marca} con {potencia} HP, fabricado en {año_fabricacion}.'

Desglosaremos ahora el código para explicar el error

Comenzaremos con  parte del  código de ejemplo, que vimos antes escrito  en Python normal; después de lo cual veremos cómo podemos desensamblar este código en el código de bytes que CPython realmente lee e interpreta.

log_object y log_invalid_object

Vamos a emplear dos funciones, que  Python posee para esto log_object(value)  y log_invalid_object(value):

def log_object(value):
    """Registra los valores pasados al parametro en consola.

    :param value: Valor a registrar.
    :return: None
    """
    try:
        Logging.log(value)
    except NameError as error:
        # Salida esperada NameErrors.
        Logging.log_exception(error)
    except Exception as exception:
        # Salida inesperada Exceptions.
        Logging.log_exception(exception, False)


def log_invalid_object(value):
    """Intenta registrar objetos no validos(value) en consola 

    :param value: Valor que se ha intentado registrar, pero que en realidad se ha ignorado 
    :return: None
    """
    try:
        Logging.log(valu)
    except NameError as error:
        # Salida esperada NameErrors.
        Logging.log_exception(error)
    except Exception as exception:
        # Salida inesperada Exceptions.
        Logging.log_exception(exception, False)

Todo el código en ambas funciones se centra en el manejo de errores.

La funcionalidad principal tiene lugar en la línea: Logging.log (valor) y Logging.log (valu), respectivamente.

En esencia, estas dos funciones lo que hacen es registrar el contenido del parámetro de valor pasado en la consola. Sin embargo, en el caso de log_invalid_object () tenemos un leve error tipográfico de valu en lugar de value.

Creemos una instancia del objeto Auto  y  luego la pasaré a ambas funciones:

# Creando Auto.
auto = Auto("Chevreolet", "Bell air", 300hp, datetime.date(1956))
# Log Auto object.
Logging.line_separator("log_object(auto)", 60)
log_object(auto)
 
# Log invalid object.
Logging.line_separator("log_invalid_object(auto)", 60)
log_invalid_object(auto)

La ejecución de este código produce una salida del objeto Auto esperada, seguida de un NameError porque nuestro error tipográfico de valu no es un nombre reconocido.

--------------------- log_object(auto) ---------------------
'Bellair' de la marca Chevrolet con 30 HP, fabricado en 1956.
{self.modelo}\'  de la marca {self.marca} con {potencia} HP, fabricado en {año_fabricacion}.'
 
----------------- log_invalid_object(auto) -----------------
[EXPECTED] NameError: name 'valu' is not defined

Si aplicaramos el metodo    dis, que es un modulo desensamblador integrado en Python, lo cual le permite es un lenguaje poderoso que nos permite mirar profundizar y ver el código de bytes real que cada una de estas funciones log_  que se generan para el intérprete CPython.

Al pasar una referencia de función al método dis.dis (), se nos proporciona una salida completa del código de bytes desensamblado que CPython interpreta durante la ejecución.

Nuestra función local  disassemble_object(value), funciona como una pequeña envoltura para este propósito:

def disassemble_object(value):
    """Salida con el objeto desensamblado pasado.

    :param value: Object to be disassembled.
    :return: None
    """
    dis.dis(value)

Para ver el bytecode de la función log_object (value) ejecutemos el código:

# Disassemble both log_ functions.
Logging.line_separator("DISASSEMBLY OF log_object()", 60)
disassemble_object(log_object)

This produces the following output:

--------------- DISASSEMBLY OF log_object() ----------------
 41           0 SETUP_EXCEPT            14 (to 16)

 42           2 LOAD_GLOBAL              0 (Logging)
              4 LOAD_ATTR                1 (log)
              6 LOAD_FAST                0 (value)
              8 CALL_FUNCTION            1
             10 POP_TOP
             12 POP_BLOCK
             14 JUMP_FORWARD            88 (to 104)

 43     >>   16 DUP_TOP
             18 LOAD_GLOBAL              2 (NameError)
             20 COMPARE_OP              10 (exception match)
             22 POP_JUMP_IF_FALSE       58
             24 POP_TOP
             26 STORE_FAST               1 (error)
             28 POP_TOP
             30 SETUP_FINALLY           16 (to 48)

 45          32 LOAD_GLOBAL              0 (Logging)
             34 LOAD_ATTR                3 (log_exception)
             36 LOAD_FAST                1 (error)
             38 CALL_FUNCTION            1
             40 POP_TOP
             42 POP_BLOCK
             44 POP_EXCEPT
             46 LOAD_CONST               1 (None)
        >>   48 LOAD_CONST               1 (None)
             50 STORE_FAST               1 (error)
             52 DELETE_FAST              1 (error)
             54 END_FINALLY
             56 JUMP_FORWARD            46 (to 104)

 46     >>   58 DUP_TOP
             60 LOAD_GLOBAL              4 (Exception)
             62 COMPARE_OP              10 (exception match)
             64 POP_JUMP_IF_FALSE      102
             66 POP_TOP
             68 STORE_FAST               2 (exception)
             70 POP_TOP
             72 SETUP_FINALLY           18 (to 92)

 48          74 LOAD_GLOBAL              0 (Logging)
             76 LOAD_ATTR                3 (log_exception)
             78 LOAD_FAST                2 (exception)
             80 LOAD_CONST               2 (False)
             82 CALL_FUNCTION            2
             84 POP_TOP
             86 POP_BLOCK
             88 POP_EXCEPT
             90 LOAD_CONST               1 (None)
        >>   92 LOAD_CONST               1 (None)
             94 STORE_FAST               2 (exception)
             96 DELETE_FAST              2 (exception)
             98 END_FINALLY
            100 JUMP_FORWARD             2 (to 104)
        >>  102 END_FINALLY
        >>  104 LOAD_CONST               1 (None)
            106 RETURN_VALUE

Esto puede parecer un poco abrumador al principio, pero estos datos en realidad son bastante fáciles de interpretar con un poco de conocimiento sobre lo que estamos viendo en cada columna. La primera columna (por ejemplo, 41, 42, 43… 48) es el número de línea real en la gama de origen para el conjunto de instrucciones correspondiente.

Por lo tanto, podemos ver que todas las siguientes instrucciones

42           2 LOAD_GLOBAL              0 (Logging)
              4 LOAD_ATTR                1 (log)
              6 LOAD_FAST                0 (value)
              8 CALL_FUNCTION            1
             10 POP_TOP
             12 POP_BLOCK
             14 JUMP_FORWARD            88 (to 104)

 Todos se generaron a partir de una sola línea de código fuente (# 42):

La columna con múltiplos de dos (0, 2, 4, etc.) es la dirección de memoria en el código de bytes subyacente para la instrucción dada. Python moderno almacena instrucciones usando dos bytes de datos, de ahí los múltiplos de dos.

La siguiente columna contiene el nombre de operación (es decir, instrucción) que debe ejecutarse, todo lo cual se puede encontrar en la documentación oficial.

La columna posterior contiene los argumentos, si corresponde, que utilizará cada instrucción en particular.

La columna final proporciona una versión amigable para los humanos de la instrucción, por lo que podemos visualizar mejor cómo la instrucción del código de bytes se correlaciona con el código fuente.

Por lo tanto, echemos un vistazo al código fuente de una sola línea 42 de Logging.log (value) y el conjunto de instrucciones de bytecode generado para ver qué está pasando:

42           2 LOAD_GLOBAL              0 (Logging)
              4 LOAD_ATTR                1 (log)
              6 LOAD_FAST                0 (value)
              8 CALL_FUNCTION            1
             10 POP_TOP
             12 POP_BLOCK
             14 JUMP_FORWARD            88 (to 104)

Comienza con LOAD_GLOBAL para cargar el nombre global Logging en la pila.

Luego carga el atributo de registro en la parte superior de la pila (TOS).

LOAD_FAST empuja una referencia a una variable local llamada value en la pila y a continuación, CALL_FUNCTION llama a la función en la pila de argumentos 1, que es el método de registro que se agregó dos instrucciones antes.

POP_TOP elimina el elemento más reciente agregado a la pila, que es el objeto de valor local.

Cada marco de ejecución contiene una pila de bloques de código, que son las agrupaciones lógicas que vemos y creamos al escribir el código fuente que está agrupado localmente.

Por ejemplo, un bucle anidado o, en este caso, un bloque try-except, está contenido dentro de un bloque de código separado en la pila.

Dado que la siguiente instrucción a la que estamos saltando con JUMP_FORWARD 88 está saliendo del final del bloque try que se encuentra en nuestro código fuente, POP_BLOCK se usa para eliminar el bloque superior (actual) de la pila de bloques de código.

Veamos en qué se diferencia este bytecode compilado para log_object, de la función log_invalid_object ligeramente modificada:

Logging.line_separator("DISASSEMBLY OF log_invalid_object()", 60)
disassemble_object(log_invalid_object)

Ignoraremos la mayoría del bytecode producido aquí, ya que es idéntico al producido por log_object, pero también tenemos el conjunto de instrucciones de la misma línea de código fuente Logging.log (valu) correspondiente que examinamos antes:

58           2 LOAD_GLOBAL              0 (Logging)
              4 LOAD_ATTR                1 (log)
              6 LOAD_GLOBAL              2 (valu)
              8 CALL_FUNCTION            1
             10 POP_TOP
             12 POP_BLOCK
             14 JUMP_FORWARD            88 (to 104)

Todo se ve exactamente igual que antes, con dos excepciones: el número de línea 58 es obviamente diferente, ya que estamos compilando una línea diferente de código fuente.

La segunda diferencia es que la tercera instrucción, cambió de LOAD_FAST 0 (value) a LOAD_GLOBAL2(valu).

¿Por qué sucedió esto?. Pues porque el compilador no puede conciliar un objeto local llamado valu, ya que el parámetro local real pasado a la función es value.

Por lo tanto, el compilador asume que valu es un nombre global e intenta cargarlo a través de LOAD_GLOBAL, y como sabemos al ejecutar la función log_invalid_object, el intérprete de CPython no será capaz de ubicar un objeto llamado valu durante la ejecución, por lo que se genera un NameError para indicarlo.

.. y todo como el diamante, antes de luz , es carbón.

J. Martí

ImportError: No module named MySQLdb

python error

ImportError: No module named MySQLdb, es un error que Python lanza cuando tiene problemas para compilar la extensión binaria, de consultas mysql.

Una solución a esto es intentar resolverlo con Python puro empleando PyMySQL

Para ello simplemente debe ser instalado de con pip.

Ver otros errores de Python

pip install pymysql 

Si estas empleando SQLAlchemy también debe cambiarse la URI, para que comience incluyendo pymysql:

SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://.....'

En dependencia de la estructura de tu código y las librerías mysql que emplea, otra solución es instalar el cliente de mysql para Python, mediante pip.

Si usas Python 3

   pip3 install mysqlclient

Si estas aun Python2

pip install mysqlclient

Tambien puedes instalar mysql-python

pip install mysql-python

Y esto es todo, espero modestamente que este post, sirva de ayuda a alguien.

Muchas gracias

El amor tiene firma de autor en las causas perdidas

R.Arjona

Los sockets en Python.

logo python

Es común, incluso puede ser habitual, que necesitemos crear una conexión entre dos programas o dispositivos al programar; pues bien, los sockets en Python y otros lenguajes, están pensados para eso. 

Los sockets son una estructura que permite la conexión entre dos aplicaciones, procesos o equipos, (IPC) estableciendo una relación cliente/servidor, que permite el intercambio de datos, incluso entre programas colocados en ordenadores diferentes.

Los sockets, pueden interpretarse como el punto final de una conexión, donde para establecerla será necesario como mínimo:

  • definir la dirección IP local y remota de los ordenadores que participan,
  • el puerto de conexión
  • y el protocolo de transporte de la información.  

La comunicación que se crea tendrá por tanto un carácter bidireccional.

La relación cliente/servidor, también significa que el comportamiento de los socket no es el mismo, en ambos casos, mientras en el cliente es el punto final de una conexión, en el servidor se comporta como una centralita telefónica, que usa sockets clientes y servidor

La fácil manipulación que ofrecen los sockets, los hace prácticamente imprescindibles, si la conexión es multiplataforma, aunque también son ampliamente usados en cualquier tipo de comunicación IPC (Inter-Process Communication), sin que sean los únicos, que existen.

Los tipos de sockets en Python:

Pueden ser de flujo (sock Stream), que emplean el protocolo  de transmisión TCP, o de datagrama (Sock_Dgram), que emplean UDP, para transmitir los datos.

El protocolo TCP (Transmission Control Protocol), difiere  en muchos elementos de UDP( User Datagram Protocol), sin embargo la forma más simplificada de explicar su diferencia, seria decir que los mensajes enviados por TCP llegan a su destino en el mismo orden en que se enviaron y los que se envían por UDP, pueden llegar en un orden diferente a como fueron enviado originalmente, además de que en el segundo no hay una forma de verificar la entrega y que es TCP, quien incorpora el concepto de puerto.

En Python, para expresar los datos de conexión para la familia de direcciones AF_INET, se emplea una lista con dos parámetros (host, puerto).

Donde host es una cadena que representa un nombre de host en notación de dominio de Internet como ‘darling.com ‘ o una dirección IPv4 como ‘100.50.200.50’, y el puerto es un entero.

Crear un socket en Python

Los sockets bajo el método TCP, son una forma común de comunicación en internet, por ejemplo, al interactuar con un navegador.

Cuando se da click sobre una dirección en el buscador, es como si escribiéramos lo siguiente en un socket cliente:

sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sck.connect(("www.mi_pagina", 80))

En este código primero creamos un objeto socket, que es del tipo cliente, al cual pasamos dos argumentos: el tipo de familia de direcciones (AF_INET), y el tipo de socket (sock-stream).

Clarificando un poco esto, aclaro que existen muchas familias de direcciones (F_UNIX, AF_INET6, AF_NETLINK, AF_TIPC, AF_CAN, AF_BLUETOOTH, AF_PACKET, AF_RDS), siendo AF_INET, la más común.
AF significa Address Family. AF_INET que bien pudo llamarse AF_INET4, se refiere a la familia de direcciones del tipo Protocolo de Internet v4 (IPv4), que emplean 32 bits, mientras AF_INET6 se refiere a familia de direccionamiento de IPv6, que utiliza 128 bits.

Volviendo al código, si bien este sería el script en el socket cliente; en el socket servidor ocurre algo más:

serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind((socket.gethostname(), 2222))
serversocket.listen(4)

O sea, creamos un objeto con las mismas propiedades del cliente, sin embargo empleamos bin(), para vincularlo a un hostname y un puerto; y finalmente ponerlo a escuchar.

Viendo el detalle; en el primer parámetro de bin(), estamos indicando a que dirección se conectará.

Usamos gethostname() en este caso, para que tome un host visible en la red, fuera de nuestro ordenador, pero podríamos emplear localhost, o 127.0.01, para que se visible solo en nuestra máquina.

Los puertos de socket, el segundo parámetro de bin(), suelen ser puertos con valores de 4 dígitos.

listen(), le indica a la librería del socket la cantidad de solicitudes máximas de conexión que deseamos poner en cola. Hemos escogido 4, que un número aceptable.

Aunque de forma general, esto es lo que ocurre al establecerse una comunicación entre sockets, que será mejor mostrarlo en un ejemplo más amplio, donde abarquemos todos los momentos.

En este ejemplo emplearemos sys(), para atrapar los errores desde el intérprete, que se produzcan en la salida en la salida del código.

SOCKET SERVIDOR

#importamos las librerias
import socket
import sys

# creamos el objeto socket 
objetoSocket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

#introducimos en una variable los datos del servidor
datos_servidor = ('localhost', 10000)
# empleamos sys.stderr para imprimir
print >>sys.stderr, 'empezando a levantar %s puerto %s' % datos_servidor

# asociamos el socket con la dirección del servidor, empleando bind() 
objetoSocket_server.bind(datos_servidor)
# para que nuestro socket sea capaz de aceptar la conexión entrante desde el cliente
# y pueda escuchar el mensaje utilizaremos dos métodos: el método accept()
# que nos devuelve una conexión abierta entre el servidor y el cliente, 
# por la cual los datos, se leen y transmiten mediante recv() y sendall() 
# respectivamente y el metodo listen(), que nos indica las cantidad maxima de 
# conexiones aceptadas

objetoSocket_server.listen(1)
while True:
     print >>sys.stderr, 'Esperando para realizar conexión'
     connection, datos_cliente = objetoSocket_server.accept()

# manejamos la conexion
try:
     print >>sys.stderr, 'conectando desde', datos_cliente
     
     while True:
          data = connection.recv(19)
          print >>sys.stderr, 'recibido "%s"' % data
          if data:
               print >>sys.stderr, 'devolviendo mensaje al cliente'
               connection.sendall(data)
          else:
               print >>sys.stderr, 'no hay mas datos', datos_cliente
               break
finally:
     connection.close()

SOCKET CLIENTE

# importamos las librerias
import socket
import sys
#creamos el objeto socket
objetoSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM 

# creamos una variable con los datos del servidor.
datos_servidor = ('localhost', 10000)
# empleamos sys.stderr para imprimir
print >>sys.stderr, 'conectando a %s puerto %s' % datos_servidor

#conectamos
objetoSocket.connect(datos_servidor)
try:
     mensaje = 'Mensaje de prueba'
     print >>sys.stderr, 'enviando "%s"' % mensaje
     '''
     empleamos sendall()para enviar la información y recv(), para   recibirla,
     los parámetros del método sendall son los datos que se van a enviar, y el 
     parámetro de la funcion  recv()m es el número máximo de bytes a aceptar.
     '''
     objetoSocket.sendall(mensaje) # enviando el mensaje
     cantidad_recibida = 0
     cantidad_esperada = len(mensaje) # recibiendo la respuesta
 
     while cantidad_recibida < cantidad_esperada: data = objetoSocket.recv(19) cantidad_recibida += len(data) print >>sys.stderr, 'recibiendo "%s"' % data

    # cerramos  el socket al concluir con el método close().
    finally:
        print >>sys.stderr, 'cerrando socket'
        objetoSocket.close()

Como un último punto en este ejemplo, es bueno añadir que el socket cliente es normalmente usado, solo para un intercambio (o un pequeño número de comunicación secuencial), de modo que una vez terminado connect() es destruido

En esencia, esta es la estructura de una conexión IPC, empleando sockets.

El concepto de los sockets en Python

Resumiendo lo visto hasta aquí, la comunicación del tipo IPC, se ejecuta mejor empleando sockets, los cuales funcionan bajo la estructura cliente servidor.

El socket cliente  tiene como función básica conectarse y solicitar o envíar información, mientras  la labor del socket servidor es crear sockets clientes y escuchar el puerto.

Dicho de otro modo: una vez creado el socket servidor, este crea un par de sockets clientes, desde los que escucha la información.

La función del socket servidor , no es mandar ningún dato o recibirlo ; sino que produce sockets clientes y cada uno de estos es creado en respuesta a algún otro socket cliente que hace connect() al host y al puerto al que el socket servidor está vinculado.

Tan pronto como el servidor crea ese socket cliente, vuelve a escuchar por más conexiones.

Los dos sockets clientes, pueden conversar entre ellos, usando un puerto asignado dinámicamente y que será reciclado cuando la conversación termine.

Más sobre los sockets en Python

Existen alternativas para manipular la conexión de manera mas efectiva; ya que una vez creada  la conexión, el bucle que empleamos anteriormente, puede funcionar de diferentes modos:

  • Crear un hilo para manejar clientsocket,
  • crear un proceso nuevo para manejar clientsocket 
  • Reestructurar el codigo para usar sockets no bloqueantes y usar select para  multiplexar entre el «socket servidor» y cualquier clientsocket  activo.

IPC

Para ejecutar conexiones IPC rápidas entre dos procesos en una misma máquina, lo aconsejable es revisar la memoria compartida o las tuberías (PIPES).

Cuando se usan  sockets  con el tipo de redirección AF_INET, es una opción aconsejable vincular el servidor  con «localhost», ya que provee un atajo alrededor de algunas capas del código de red, que funciona en casi todas las plataformas.

Los verbos send y recv

Los verbos send y recv operan en los buffers de red y están enfocados a manejarlos; y debido a ello, no  están obligados a manejar obligatoriamente, todos los bytes que se les entrega, o se espera qué entreguen.

Esto crea la necesidad de llamarlos nuevamente hasta que el mensaje haya sido tratado por completo.

Como devuelven resultados cuando el buffer se llenado (send) o vaciado(recv); cuando recv() retorna 0 bytes es porque al otro lado se ha cerrado , o está en el proceso de cerrar la conexión y si ya hemos dicho que se recicla después del close(), entonces no recibirás  datos de esta conexión, nunca más.

Si la conexión no se ha interrumpido, nuestro recv() podría esperar eternamente, porque el socket no dirá, cuando no hay más nada por leer.

Por tanto, otra practica a tener en cuenta es saber qué hacer con el limite de la conexión, cerrarla, darle una longitud fija o delimitarla; pero, no hablaré en este articulo -que ya se ha hecho muy largo- de este tema.

Cerrar los sockets

Para Python cuando un socket es eliminado por el recolector de basura, automáticamente llama a close().

Esto elimina la posibilidad de que quede eternamente abierto, aunque confiar en esto es una mala práctica, porque puede no evitar que el socket del otro lado espere indefinidamente, pensando que su pareja solo esta siendo lenta y TCP es un protocolo confiable, que esperará un largo tiempo antes de rendirse con una conexión.

Por ello, lo recomendado es llamar a close(), siempre y cuando no estes usando hilos.

Sockets bloqueantes y no bloqueantes.

Todo lo que hemos visto hasta aquí, es el procedimiento  para un socket bloqueante

En Python,  se usa socket.setblocking(False) para que un socket no sea bloqueante.

Se diferencia en que send()recv()connect() y accept() pueden retornar sin haber hecho nada.

Debido a ello, se necesita leer  el retorno de un modo óptimo. Un buena solución es emplearse la función select()

Usando select.

ready_to_read, ready_to_write, in_error = \
               select.select(
                  potential_readers,
                  potential_writers,
                  potential_errs,
                  timeout)

select() se le pasan tres listas: la primera con todos los sockets que puede intentar leer; la segunda con todos los sockets que puede intentar escribir, y la tercera, qué usualmente se deja vacía, incluye a aquellos a los que se quiera verificar los errores.

Teniendo en cuenta su complejidad, es muy probable que necesites colocar un socket en más de una lista.

Aunque la llamada a select(), se comporta como bloqueante, acepta darle un tiempo de espera largo.

El retorno de la función devuelve igualmente tres listas, que contienen los sockets que son realmente legibles, escribibles y con error. Cada una de estas listas es un subconjunto (posiblemente vacío) de la lista correspondiente que se pasó a select().

Cuando un socket está en la lista retornada legible, eso significa que una llamada a recv() en este socket va a retornar algo, y lo mismo para la lista de escribibles, ese socket será capaz de mandar algo  y eso solo significa que el espacio de salida del buffer de red está disponible.

En caso de que se necesite revisar a un socket servidor, debe ir en la lista de potenciales legibles y si retorna como legible es casi seguro que una llamada a accept() va a funcionar.

Si se posee un nuevo socket para llamar a connect() y conectarlo con otro, debe ir en la lista de potenciales escribibles,  y si retorna como escribible, es que seguramente esta conectado.

select() puede ser útil incluso con sockets bloqueantes, ya que  el socket retorna como leíble cuando hay algo en el buffer, no obstnte vale aclarar que esto no sirve de ayuda con el problema de determinar si el  socket al otro lado culminó la conexión, o solo está ocupado.

Y hasta aquí, espero modestamente, que esto sirva de ayuda a alguien.

Tres cosas necesitan las ovejas para andar en manada, el miedo al perro, la voz de amo y que la de atrás empuje, por miedo a quedarse sola.

Y.

Crear un mapa con Folium en Python

logo python

En este articulo, mostraré como crear un mapa con Folium en Python, por diferentes vías.

Folium es una librería fantástica, que nos permite crear mapas de un modo simple y ágil y que puede ser una magnifica alternativa a basemap.

La forma básica de crear un mapa en Folium es :

import folium
from folium import plugins
import ipywidgets
import pandas as pd
import numpy as np

folium.Map()#aqui llamamos al mapa simple 

Otra forma simple, es crear el mapa, acotando elemento como el zoom, el área,  la escala  y tamaño del mapa y una dirección especifica. Esta ultima mediante su latitud y longitud.

folium.Map(location=[39.473861, -0.360830], zoom_start=80, width=500, height= 600, control_scale=True)

Otros artículos sobre Python

Esta muestra además la escala y se puede controlar el tamaño del mapa

Controlar el tamaño del mapa

También podemos controlar el tamaño del mapa es empleando  el modulo figure() de la librería branca().

from branca.element import Figure

#folium.Map()
map_1= folium.Map(location=[39.473861, -0.360830], zoom_start=80, control_scale=True)
map_1
fig = Figure(width=1000, height=500)
fig.add_child(map_1)
fig

Guardar el mapa

Para guardar el mapa en folium, basta con darle un ruta al  método save()

Tipos de mapas con widgets

Con folium es fácil añadir widgets a los mapas, que los hacen muy útiles y amplian mucho las posibiidades de visualización.

En el ejemplo mostramos diferentes vistas de un mapa, empleando los widgets:

#seleccion de los widgets
select_widgets=ipywidgets.Select( 
    options=['Open Street Map', 'Terrain', 'Watercolor', 'Positron', 'Dark Mater'],
    value = 'Open Street Map',
    description ='Tipos de mapa:',
    disable= False)
def selectMap(maptype):
    if maptype == "Open Street Map":
        display(folium.Map(location=[39.473861, -0.360830], zoom_start=80, control_scale=True))
    if maptype == "Terrain":
        display(folium.Map(location=[-12.055815, -77.0567980], zoom_start=50, control_scale=True))
    if maptype == "Watercolor":
        display(folium.Map(location=[20.0521337, -75.860336], zoom_start=10, tiles='Stamen Watercolor', control_scale=True))
    if maptype == "Positron":
        display(folium.Map(location=[40.410610, -3.490617], zoom_start=10, tiles='CartoDB Positron', control_scale=True))
    if maptype == "Dark Mater":
        display(folium.Map(location=[40.410610, -3.490617], zoom_start=10, tiles='CartoDB Dark_Matter', control_scale=True))

#interactuando entre el widget y la funcion
ipywidgets.interact(selectMap, maptype=select_widgets)

Hay mucho mas que sacar de Folium, como mapas de calor, así que te invito a investigar esta útil librería y sacarle jugo a sus enormes posibilidades.

Espero que esto sirva de ayuda a alguien. Muchas gracias.

Pocos saben lo mucho que debemos saber, para darnos cuenta de lo poco que sabemos

R. Tagore

Error EOFError en Python

python error

El error EOFError, es un tipo de error que suele aparecer con cierta regularidad en Python y que podemos manipular con excepciones.

Se genera cuando una de las funciones integradas input () o raw_input () alcanza una condición de fin de archivo (EOF) sin leer ningún dato.

Esto ocurre cuando le hemos pedido al usuario una entrada pero no hemos proporcionado ninguna entrada en el cuadro de entrada.

Este error, a veces se experimenta al usar IDE en línea.

Podemos solucionar este problema usando try y except, para manipular la excepción.

Podemos solucionar este problema usando try y except, para manipular la excepción.

Un código como este, arrojará un error del  tipo EOFerror

Podemos manejarlo de la siguiente forma:

n = int(input())
print(n * 10)

Podemos manejarlo de la siguiente forma:

try:
    n = int(input())
    print(n * 10)
    
except EOFError as e:
    print(e)

Lee sobre otros errores de Python en este blog

Hay que sembrar un árbol, un ansia, un sueño, un hijo, porque la vida es eso , sembrar, sembrar, sembrar

J. A. Buesa

NameError: name exit is not defined

python error

En este post veremos el NameError: name exit is not defined, en  Python que cómo indica es un error de nombre, y que podemos solucionar con cierta facilidad.

Ver más errores en Python en este blog

La solución a esto es importar sys y luego importar exit.

Seria algo así:

from sys
import exit
exit()

También puede intentar esta vía

import sys
sys.exit()

Y esto es todo, debería funcionar.

Espero sinceramente que este post, sirva de ayuda  a alguien y muchas gracias.

Entrena duro y en silencio, que el éxito sea tu grito

D.
Translate »