miércoles, 21 de diciembre de 2022

4.- Django - Cargadores de Plantillas.

  ¿Te pierdes entre tantos temas? 📚✨ Descubre todo lo que ofrece este blog en un solo vistazo [👉 Ver índice completo]

Hasta ahora para cargar una plantilla creábamos una variable y usábamos el método "open", le especificamos la ruta de la plantilla. Después utilizábamos el objeto "Template" para pasarle por parámetro el objeto que acabamos de cargar y lo leíamos con el metodo "read".  Y más tarde le decíamos que renderizará ese objeto Template utilizando un contexto


views.py

...
# Vistas

def saludo(request):
    doc_externo = open(
        "/home/chema/Cursos/DJANGO/Proyecto1/plantillas/plantilla.html")
    plantilla = Template(doc_externo.read())
    doc_externo.close()

    nombre = "Antonio"
    fecha_actual = datetime.datetime.now()

    ciudades = ["Barcelona", "Madrid", "León", "Caceres"]

    # Al contexto hay que pasarle un diccionario que se usara para transferir a el valor
    # a la plantilla
    contexto = Context(
        {"nombre_usuario": nombre, "date": fecha_actual, "lugares": ciudades})
    documento = plantilla.render(contexto)
    return HttpResponse(documento)
...


Hay una forma más eficiente de hacer todo esto que es utilizando un cargador o "loader". Consiste en decirle al proyecto de Django que las plantillas se encuentran en un directorio en concreto, al que normalmente se denomina templates (aunque puedes llamarlo como quieras, aquí seguiremos llamándole plantillas). Después cuando vayamos a utilizar una plantilla, todo lo anterior se va a hacer automáticamente, ahorrando recursos y varias líneas de código.

Primeramente debemos decirle a Django donde está la carpeta que contiene nuestras plantillas. Esto se hace en el archivo settings.py y buscamos una variable llamada TEMPLATES. Es una lista que contiene un diccionario una de cuyas claves es DIRS que por defecto aparece vacío.

Nota: Como veremos mas adelante, cuando creemos una aplicación, si utilizas como nombre del directorio "templates", que es el que se utiliza por defecto, y no un nombre personalizado como "plantillas" que he usado yo, no tendrás que registrar el directorio de las plantillas en settings.py. Pero de momento como no hemos creado ninguna aplicación, si no que estamos trabajando con el directorio del proyecto, hay que registrar la ruta.


TEMPLATES dentro de settings.py


Es aquí donde pondremos la ruta del directorio que contiene nuestras plantillas. En mi caso se llama "plantillas" pero puedes usar el nombre que quieras. Lo modificamos para que incluya la ruta de las plantillas, en mi caso:


settings.py

...
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ["/home/chema/Cursos/DJANGO/Proyecto1/plantillas"],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]


Una vez hecho esto, importamos el cargador o "loader" en views.py:

from django.template.loader import get_template

views.py

from django.http import HttpResponse
import datetime
# Al utilizar un cargador la siguiente línea no hace falta.
# from django.template import Template, Context
from django.template.loader import get_template

# Vistas

def saludo(request):
    doc_externo = open(
        "/home/chema/Cursos/DJANGO/Proyecto1/plantillas/plantilla.html")
    plantilla = Template(doc_externo.read())
...

Después de importar el loader borramos (yo lo voy a comentar para ver la diferencia) la línea que cargaba el programa, creaba el objeto "Template" y cerraba el documento.

views.py

def saludo(request):
    # Al utilizar un cargador esto no hace falta ya.
    # doc_externo = open("/home/chema/Cursos/DJANGO/Proyecto1/plantillas/plantilla.html")
    # plantilla = Template(doc_externo.read())
    # doc_externo.close()

    nombre = "Antonio"
    fecha_actual = datetime.datetime.now()

    ciudades = ["Barcelona", "Madrid", "León", "Caceres"]

    doc_externo = get_template("plantilla.html")

    contexto = {"nombre_usuario": nombre, "date": fecha_actual, "lugares": ciudades}
    documento = doc_externo.render(contexto)
    return HttpResponse(documento)

Y todo va a quedar más sencillo. 

Creamos una variable (doc_externo) que cargará la plantilla o plantilla que queramos usando "get_template".

 Date cuenta que ya no hay que especificar la ruta de la plantilla. Ya no necesitamos tampoco ni el objeto Template ni el objeto context. Ahora sencillamente al doc_externo que ha cargado la plantilla lo renderizamos con el método render al que tenemos que pasar un diccionario y no un objeto "context" como hacíamos antes.


Y LO MAS PRACTICO VIENE AHORA ->

Incluso podemos abreviar más el código si utilizamos atajos o "shortcut functions" que Django nos facilita. Aquí nos viene una función muy útil, llamada "render()" que hará que podamos prescindir de casi todo y nos quedará todo el proceso de carga y renderizado en una única línea. Para ello primero tenemos que importar en views.py lo siguiente:

from django.shorcuts import render 

y veréis en lo que se nos queda el código.

views.py (archivo final para cargar una plantilla externa usando el menor código)

from django.http import HttpResponse
import datetime

from django.shortcuts import render

# Vistas

def saludo(request):
    nombre = "Antonio"
    fecha_actual = datetime.datetime.now()

    ciudades = ["Barcelona", "Madrid", "León", "Caceres"]
    
    contexto = {"nombre_usuario": nombre, "date": fecha_actual, "lugares": ciudades}
    
    return render(request, "plantilla.html", contexto)


En vez de retornar un objeto HttpResponse como hicimos hasta ahora, retornamos un objeto render en el que ya especificamos como primer argumento el "request", como segundo el nombre de la plantilla entre comillas y como tercero podemos pasarle el contexto como una variable o pasarle directamente el diccionario. Así de fácil y con una sola línea de código podemos renderizar una plantilla con un determinado contexto.

Próximo Post - 5. Plantillas incrustadas y herencia de plantillas.

lunes, 12 de diciembre de 2022

3.- Django - Plantillas II, variables y propiedades en la plantilla.

 ¿Te pierdes entre tantos temas? 📚✨ Descubre todo lo que ofrece este blog en un solo vistazo [👉 Ver índice completo]

En el apartado anterior vimos como crear y cargar plantillas desde las vistas. En este apartado vamos a profundizar más y veremos como pasar información a las plantillas, para lo cual utilizaremos un tipo de dato de Python, como son los diccionarios dentro de los contextos.

Seguimos con el mismo ejemplo usado en el capitulo anterior donde una de la vistas se llamaba "saludo" y cargábamos un documento externo, la plantilla, desde un directorio creado al efecto.

Imaginemos que queremos pasarle un nombre de usuario a la plantilla desde la vista para que la muestre en la página web y le de la Bienvenida.

Por ejemplo que Ponga "Bienvenido Pedro" o lo que tu quieras.

Empezamos creando en las vistas, views.py, una variable "nombre" que recoja el nombre que le queramos pasar. Luego dentro del contexto y siempre a través de un diccionario usamos una clave "nombre_usuario" cuyo valor será renderizado posteriormente al mostrar la página web.

views.py: archivos de vistas.

...
# Vistas
def saludo(request):
    doc_externo = open("/home/chema/Cursos/DJANGO/Proyecto1/plantillas/plantilla.html")
    plantilla = Template(doc_externo.read())
    doc_externo.close()

    nombre = "Antonio"

    # Al contexto hay que pasarle un diccionario que se usara para transferir a el valor
    # a la plantilla
    contexto = Context({"nombre_usuario": nombre})
    documento = plantilla.render(contexto)
    return HttpResponse(documento)

...

Para finalizar en la plantilla, ponemos donde queramos que se renderice posteriormente esta información usando flechas dobles {{ }}. Tiene su lógica puesto que recuerda que en Python se usan las flechas sencillas para crear los diccionarios {}.

plantilla.html

<!DOCTYPE html>
<html lang="es">
<head>
     <meta charset="UTF-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>Fecha Servidor</title>
</head>
<body>
      <h3>
         ¡Hola Mundo! He sido cargado desde una plantilla.         
      </h3> 
      <p>
            Bienvenido {{nombre_usuario}}
      </p>  
</body>
</html>


Salida:


variable renderizada en la plantilla

Podemos pasar tantas claves como queramos e incluso usar la metodología del punto de las clases para pasar valores. Por ejemplo aprovechando que habíamos importado la función "datetime" vamos a mostrar la fecha actual del siguiente modo:

views.py: archivos de vistas.

...
# Vistas
def saludo(request):
    doc_externo = open("/home/chema/Cursos/DJANGO/Proyecto1/plantillas/plantilla.html")
    plantilla = Template(doc_externo.read())
    doc_externo.close()

    nombre = "Antonio"
    fecha_actual = datetime.datetime.now()

    # Al contexto hay que pasarle un diccionario que se usara para transferir a el valor
    # a la plantilla
    contexto = Context({"nombre_usuario": nombre, "date": fecha_actual})
    documento = plantilla.render(contexto)
    return HttpResponse(documento)

...
y modificamos la plantilla:

plantilla.html

<!DOCTYPE html>
<html lang="es">
<head>
     <meta charset="UTF-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>Fecha Servidor</title>
</head>
<body>
      <h3>
         ¡Hola Mundo! He sido cargado desde una plantilla.         
      </h3> 
      <p>
            Bienvenido {{nombre_usuario}}
      </p>  
      <p>
            Hoy es {{date.day}} - {{date.month}} - {{date.year}}
      </p>
</body>
</html>

Salida:


inclusión de variable en plantillas


A continuación vamos a ver como pasar una lista a una plantilla. Seguimos con el ejemplo y vamos a pasarle una lista con ciudades.

El proceso es igual que en los casos anteriores. Creamos la lista y se la pasamos a través del contexto mediante un diccionario que contendrá la clave "lugares" y como valor la lista a pasar.

views.py: archivos de vistas.

...
# Vistas
def saludo(request):
    doc_externo = open("/home/chema/Cursos/DJANGO/Proyecto1/plantillas/plantilla.html")
    plantilla = Template(doc_externo.read())
    doc_externo.close()

    nombre = "Antonio"
    fecha_actual = datetime.datetime.now()

    ciudades = ["Barcelona", "Madrid", "León", "Caceres"]

    # Al contexto hay que pasarle un diccionario que se usara para transferir a el valor
    # a la plantilla
    contexto = Context({"nombre_usuario": nombre, "date": fecha_actual, "lugares":ciudades})
    documento = plantilla.render(contexto)
    return HttpResponse(documento)

...

y modificamos la plantilla para que sean mostrados. La lista se muestra tal cual.

plantilla.html

...
<body>
      <h3>
         ¡Hola Mundo! He sido cargado desde una plantilla.         
      </h3> 
      <p>
            Bienvenido {{nombre_usuario}}
      </p>  
      <p>
            Hoy es {{date.day}} - {{date.month}} - {{date.year}}
      </p>
      <p> En todas estas ciudades:
            <br/><br/>
            {{lugares}}
      </p>
</body>
...

Salida:

Insertar una lista en una plantilla

¿Y si quisieramos acceder a un solo elementos de la lista? Pues lo hariamos directamente en la plantilla con la nomenclatura del punto. En el ejemplo si solo quisiéramos mostrar "Caceres" (las listas en python comienzan en el elemento 0) el código sería:

plantilla.html

...
<body>
      <h3>
         ¡Hola Mundo! He sido cargado desde una plantilla.         
      </h3> 
      <p>
            Bienvenido {{nombre_usuario}}
      </p>  
      <p>
            Hoy es {{date.day}} - {{date.month}} - {{date.year}}
      </p>
      <p> En todas estas ciudades:
            <br/><br/>
            {{lugares.3}}
      </p>
</body>
...

También podríamos haberlo hecho mediante Python en el archivo de vistas y pasarle solo el elemento que nos interese.


Salida:

Seleccionando un elemento de una lista

En los ejemplos anteriores hemos utilizado varias veces la nomenclatura del punto. Vamos a hacer un inciso para ver el orden jerárquico que usa Django cuando se encuentra con un punto. Es decir que hace Django cuando encuentra un punto en un plantilla. En este orden:

- Lo primero que hace es buscar un Diccionario. Es decir a ver si ese punto corresponde con un elemento de un diccionario.

- Si no lo encuentra mira a ver si ese mismo punto corresponde a un Atributo o Propiedad correspondiente a una clase.

- En tercer lugar pasa a mirar si se trata de un Método perteneciente a un objeto o una clase.

- Y por último mira a ver si es un elemento de una Lista (como en el ejemplo previo)


Bucles en plantillas de Django.

¿y si quisiéramos que las ciudades aparezcan una debajo de otra? Pues se puede hacer de varias formas pero para avanzar un poco vamos a usar los bucles en plantillas con Django.

Los bucles en plantillas van, NO entre dos llaves, si no entre una llave simple y utilizando el signo de porcentaje. Hay que poner una etiqueta de apertura del bucle y otra de cierre. Al igual que en Python se usa la palabra reservada "for" de la siguiente forma:

plantilla.html

...
<body>
      <h3>
         ¡Hola Mundo! He sido cargado desde una plantilla.         
      </h3> 
      <p>
            Bienvenido {{nombre_usuario}}
      </p>  
      <p>
            Hoy es {{date.day}} - {{date.month}} - {{date.year}}
      </p>
      <p> En todas estas ciudades:</p>
      <p>
            <ul>
            {% for ciudad in lugares %} <!-- Llave de apertura -->
                  <li>{{ciudad}}</li>
            {% endfor %} <!-- LLave de cierre -->
            </ul>
      </p>
</body>
...

Salida:

bucle for en Django


Condicionales.

Al igual que cualquier lenguaje de programación también podemos usar condicionales. Se construye de la misma forma que hemos visto antes para los bucles, con una etiqueta de apertura y otra de cierre y usando una llave y la palabra reservada "if". Por ejemplo vamos a modificar la plantilla para que nos indique si estamos en la primera quincena del mes o en la segunda.

La sintaxis sería la siguiente:

plantilla.html

...
      <p>
            Bienvenido {{nombre_usuario}}
      </p>  
      <p>
            Hoy es {{date.day}} - {{date.month}} - {{date.year}}.
            {% if date.day < 15 %}
                  Estamos en la primera quincena del mes.
            {% else %}
                  Estamos en la segunda quincena del mes.
            {% endif %}
      </p>
      <p> En todas estas ciudades:</p>
      <p>
...

Es casi igual que en Python salvo porque no se ponen los dos puntos al final de la sentencia a evaluar.

Salida:

condicional en Django



Puedes encontrar más información sobre bucles, condicionales y otra multitud de etiquetas que puedes usar en Django ya construidos en la documentación en la sección "Built-in template tags and filters"

Otra diferencia con Python es a la hora de utilizar los métodos. Me explico. Imagina que en Python tenemos un string y queremos ponerlo en mayúsculas. Por ejemplo tengo la palabra "gacela" y quiero ponerla en mayúsculas:

"gacela".upper()

Sin embargo en Django para aplicar en la plantilla un método a este mismo string usaríamos el mismo método pero con una diferencia, prescindiríamos de los paréntesis finales ()

"gacela".upper

En el ejemplo en el que estamos trabajando si queremos poner el nombre del usuario en mayúsculas lo haríamos de la siguiente forma:

...
      <p>
            Bienvenido {{nombre_usuario.upper}}
      </p>  
      <p>
            Hoy es {{date.day}} - {{date.month}} - {{date.year}}.
...

Salída:

Condicionales en Django


Comentarios en Plantillas de Django:

Los comentarios de una sola línea tienen esta estructura:

{# Texto del comentario #}

Los de varias líneas esta otra:

{% comment %}
    texto del comentario
    texto del comentario
{% endcommnent %}


Filtros en Plantillas. (built-in filters reference)

Son elementos que se usan para filtrar la información o transformarla de alguna manera. Con los filtros puedes hacer muchas cosas en las plantillas y no solo modificar strings o texto, sino también sumar dos números, ordenar listas y muchas más. Lo mejor es ver la documentación pero vamos a ver un ejemplo.

El filtro se usa poniendo después de la variables que se quiere filtrar un "pipeline" que es el símbolo "|" y el filtro a utilizar.

Usaremos filtros para que todos los nombres de las ciudades se pongan en Mayúsculas y también para que nos diga si el día es un numero par o impar. 

plantilla.html

<!DOCTYPE html>
<html lang="es">
<head>
     <meta charset="UTF-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>Fecha Servidor</title>
</head>
<body>
      {# COMENTARIO EN UNA PLANTILLA DE DJANGO de una sola línea #}
      {% comment %}
            COMENTARIO
            de varias lineas
      {% endcomment %}
      <h3>
         ¡Hola Mundo! He sido cargado desde una plantilla.         
      </h3> 
      <p>
            Bienvenido {{nombre_usuario}}
      </p>  
      <p>
            Hoy es {{date.day}} - {{date.month}} - {{date.year}}.
            {% if date.day < 15 %}
                  Estamos en la primera quincena del mes.
            {% else %}
                  Estamos en la segunda quincena del mes.
            {% endif %}

            {# Filtro para mostrar si el dia es un número par o impar. #}
            {% if date.day|divisibleby:"2" %}
                  <p>El día de hoy es un número par.</p>
            {% else %}
                  <p>El día de hoy es un número impar.</p>

            {% endif %}
      </p>
      <p> En todas estas ciudades:</p>
      <p>
            <ul>
            {% for ciudad in lugares %} <!-- Llave de apertura -->
                  <li>{{ciudad|upper}}</li>
            {% endfor %} <!-- LLave de cierre -->
            </ul>
      </p>
</body>
</html>

Salida:

uso de filtros en plantillas de Django


No obstante conviene no abusar del uso tanto de las estructuras de control, como de los filtros ya que la filosofía de Django es que la parte lógica esté en una parte "views.py" y el diseño en otro (en las plantillas).

miércoles, 7 de diciembre de 2022

2.- Django - Contenido dinámico e Introducción de Parámetros en URL.

 ¿Te pierdes entre tantos temas? 📚✨ Descubre todo lo que ofrece este blog en un solo vistazo [👉 Ver índice completo]

En la primera página que mostramos en el post anterior, correspondiente al "Hola Mundo", se mostraba un contenido estático. Aunque cargaras la página web varias veces siempre se mostraba lo mismo. 

Vamos a diseñar ahora una página que nos muestre la hora y fecha del servidor, con lo que cada vez que actualices la página se mostrará una información diferente - Dinámico -. Además, podemos pasar esta información formateada, usando como parámetro del método HttpResponse con código HTML, en vez de un string.

Y ¿Cómo hacemos esto?

Pues partimos del ejemplo del capitulo anterior. En el archivo views.py,  creamos una vista más de la siguiente forma:

views.py

from django.http import HttpResponse
import datetime

# Vistas
...
# Nueva vista que mostrará la hora actual.
def fecha_actual(request):

    date = datetime.datetime.now()

    # Estructura de un documento tipo html5
    documento = f"""
    <!DOCTYPE html>
    <html lang="es">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Fecha Servidor</title>
    </head>
    <body>
        <h2>
            Fecha y hora Actuales: {date}
        </h2>    
    </body>
    </html>
    """
    return HttpResponse(documento)
Para empezar importamos la biblioteca datatime ya que es la que utilizaremos para mostrar la fecha y hora actuales. 

Creamos la variable date que almacenará esa fecha y hora.

Creamos la nueva vista. La Función de esta vista la he llamado "fecha_actual". Para darle formato a la salida utilizamos la variable documento que recoge la estructura básica de un documento html5. Al final no es más que un string con lo que podemos introducir información, como lo haríamos normalmente en Python - f"texto {variable}" -

El siguiente paso es registrar esa vista en el archivo que guarda las urls, urls.py.

urls.py

from django.contrib import admin
from django.urls import path
from Proyecto1.views import saludo, fecha_actual

urlpatterns = [
    path('admin/', admin.site.urls),
    path('saludo/', saludo),
    path("time_server/", fecha_actual),
]
Importamos la función fecha_actual al principio. Luego para acceder a la vista hay que usar el nombre "time_server" que hace referencia a la vista o función "fecha_Actual". Como comentamos en el post anterior el nombre para acceder a la vista "time_server" no tiene que ser necesariamente el nombre de la función "fecha_actual" aunque es lo más recomendable.

Vamos a ver si funciona. Ejecutamos el servidor de pruebas con:

$ python manage.py runserver

Salida:

muestra fecha servidor en pantalla


Puedes ver como va cambiando refrescando el navegador con F5.


Paso de Parámetros a través de la URL.


Para ver como se hace, vamos a ver un ejemplo, en el que pasando dos números a través de una vista nos muestre su suma.

Como en los casos anteriores lo primero es crear la función de la vista.

IMPORTANTE: Por defecto los parámetros que se pasan a través de una URL son de tipo string. Por eso si necesitamos, como en este caso, que sean numéricos hay que ponerlos con este formato:

/<int: parámetro>

Comentar que aparte de <int:loquesea> también se pueden utilizar los siguientes comandos para modificar el tipo de parámetros que introducimos en la Url:

  • string: Acepta cualquier texto sin barras (por defecto). Si no ponemos nada en el parámetro como ya dijimos lo considera como un string, una cadena de texto.
  • int: para convertirlo en enteros
  • float: para  valores reales, con decimales.
  • path: Acepta cadena de caracteres con barras


Otra opción es sabiendo que al pasárselos a la función, estos datos que son de tipo string, los convirtamos luego dentro de la función al tipo de datos que necesitemos usando Python. (por ejemplo int(parametro) )

Dicho lo cual la forma general de pasar los parámetros es:

def nombre_vista(request, parametro1, parametro2,...,parametro_n):
        -----
        -----
        -----
        return HttpResponse(documento)


Creamos la función de la nueva vista.

views.py

# Suma dos números pasados como parámetros en la Url
def suma_numeros(request, numero_1, numero_2):
    documento = documento = f"""
    <!DOCTYPE html>
    <html lang="es">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Fecha Servidor</title>
    </head>
    <body>
        <h3>
            La suma de {numero_1} más {numero_2} = {numero_1 + numero_2}
            <hr/>
        </h3>    
    </body>
    </html>
    """
    return HttpResponse(documento)

Para registrar la URL la forma general es:

path("Nombre_Url/<parametro_1>/<parametro_2>/..../<parametro_n>/", nombre_vista)

en nuestro ejemplo, como necesitamos que los parámetros se pasen como enteros para sumarlos:

urls.py

from django.contrib import admin
from django.urls import path
from Proyecto1.views import saludo, fecha_actual, suma_numeros

urlpatterns = [
    path('admin/', admin.site.urls),
    path('saludo/', saludo),
    path("time_server/", fecha_actual),
    path("suma_numeros/<int:numero_1>/<int:numero_2>/", suma_numeros),
]

Como siempre, importamos la función y luego registramos la URL.

Salida:

paso de parametros a través de url
Plantillas - Son cadenas de texto que pueden tener código Html o ser texto plano simplemente. Sirven para separar la parte lógica de la parte visual del proyecto. Aunque hay muchas formas de utilizar las plantillas la más habitual es guardar todo el código HTML en un documento aparte y en otra carpeta distinta y luego la cargarla en nuestra vista.

Para crear una plantilla, básicamente seguimos tres pasos:

1.) Creación de un objeto tipo Template.
2.) Creación de un contexto (Contenido dinámico, variables, funciones etc)
3.) Renderizado del template.

Vamos a pasar todo esto a código con el proyecto que estamos usando desde el post inicial. En el proyecto que estamos usando ya teníamos una función en views.py llamada "saludo" que nos devolvía un texto plano. Vamos a hacer que nos devuelva el mismo texto pero usando una plantilla para que nos sirva de ejemplo.

Vamos a crear un nuevo archivo que será la plantilla que vamos a crear y la guardaremos también en una carpeta nueva, separada que por ejemplo podemos llamar "plantillas", aunque normalmente se suele llamar "templates".

directorio para plantillas


plantilla.html (guardada en directorio "plantillas")

<!DOCTYPE html>
<html lang="es">
<head>
     <meta charset="UTF-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>Fecha Servidor</title>
</head>
<body>
      <h3>
         ¡Hola Mundo! He sido cargada desde una plantilla.
      </h3>    
</body>
</html>

Ahora volvemos a el archivo views.py y modificamos la función saludo para que cargue la plantilla. Aunque posteriormente lo haremos con cargadores vamos a empezar poco a poco y en este ejemplo lo haremos manualmente.

Lo primero que haremos es importar al comienzo del programa la clase Template y Context

views.py

from django.http import HttpResponse
import datetime
from django.template import Template, Context

# Vistas
def saludo(request):
    doc_externo = open("/home/chema/Cursos/DJANGO/Proyecto1/plantillas/plantilla.html")
    plantilla = Template(doc_externo.read())
    doc_externo.close()
    # Aunque no hay contenido dinámico, hay que crear el contexto.
    contexto = Context()
    # Renderizamos el contenido
    documento = plantilla.render(contexto)
    return HttpResponse(documento)

...
Si vamos al archivo de vistas, views.py, en vez de trabajar con texto incrustado lo vamos a hacer con una plantilla ya creada, para cargarla y renderizarla. 

Empezamos creando una variable, doc_externo, que utiliza el método open para cargar la plantilla. Tenemos que especificar la ruta donde encontrar el documento. (Ojo que para especificar la ruta hay que usar esta barra "/" sobretodo si estás en windows)

Una vez hecho esto creamos el objeto de tipo Template que asignare a una variable que puedes llamar como prefieras, plantilla en mi caso. Utilizamos .read() para leerla. Ya tenemos cargado el documento.

Y como lo tenemos cargado voy a cerrar el fichero para que no ocupe memoria con doc_externo.close().

Como el ejemplo es muy sencillo y no lleva contenido dinámico, ni información adicional la variable contexto es igual a la clase Context pero sin contenido. 

Para finalizar renderizamos el contenido.

Si ejecutamos el servidor y lo probamos con localhost/saludo/ nos debería funcionar.

Todo lo anterior es para tener la idea global de como funciona la carga de plantillas, ya que como veremos luego existen métodos más eficientes y sencillos de hacerlo, como veremos en el próximo post.

Próximo. Post 3.- Plantillas, variables y propiedades en la plantilla.

sábado, 19 de noviembre de 2022

1.- Django - Instalación y Primera Página.


 ¿Te pierdes entre tantos temas? 📚✨ Descubre todo lo que ofrece este blog en un solo vistazo [👉 Ver índice completo]

¿Que es Django?

De forma muy resumida podemos decir que es un "framework" de Python para crear entornos web. 


1) Instalación.

Se puede instalar en local o también, que suele ser lo normal, en un entorno virtual. Todos los ejemplos que siguen están realizados en un entorno virtual.

Para instalarlo vamos a su página y buscamos la sección de descargas. Ni que decir tiene que tienes que tener Python instalado en tu ordenador para poder ejecutar Django. Personalmente como estoy en Linux, lo voy a instalar con: 

$ sudo pip3 install Django

o también,  a fecha en la que he escrito esta entrada, la última versión con:

pip install Django==4.1.3

Para ver si esta correctamente instalado, entramos en la consola de Python y tecleamos:

(miEntorno) chema@lenovo:~/Cursos/DJANGO$ python
Python 3.10.6 (main, Nov  2 2022, 18:53:38) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>> django.VERSION
(4, 1, 3, 'final', 0)


2) Creación de un proyecto.

Un Proyecto se organiza como un grupo de aplicaciones individuales que trabajan juntas para que el proyecto funcione como un todo.

Empezaremos creando una carpeta donde guardar el proyecto (DJANGO en mi caso). Entramos en ella y desde el terminal, podemos hacerlo de dos formas:

a) $ django-admin startproject Nombre_Proyecto

(como nombre de proyecto escogí Proyecto1)

Se creará una carpeta con el nombre que le hayamos puesto al proyecto y si entramos en ella veremos el siguiente esquema de directorio:

Proyecto1



o

b) $ django-admin startproject Nombre_Proyecto .

Importante el punto final. La diferencia está en que de esta forma se nos crea el proyecto con forma de directorio para que sea más fácil desplegarlo. Quedaría así:

Proyecto1


Cuestión de gustos o funcionalidad el elegir una y otra. (el directorio miEntorno es el entorno virtual que he creado, no se instala con Django).

El archivo manage.py es muy importante porque nos permite interactuar con los proyectos Django de varias formas. Si vamos a la consulta y ejecutamos:

$ ./manage.py help o bien python manage.py help

Nos ofrece una salida con todas las instrucciones y comandos que puede ejecutar. (entre ellos el parámetro startproject ya visto)

(miEntorno) chema@lenovo:~/Cursos/DJANGO$ ./manage.py help

Type 'manage.py help <subcommand>' for help on a specific subcommand.

Available subcommands:

[auth]
    changepassword
    createsuperuser

[contenttypes]
    remove_stale_contenttypes

[django]
    check
    compilemessages
    createcachetable
    dbshell
    diffsettings
    dumpdata
    flush
    inspectdb
    loaddata
    makemessages
    makemigrations
    migrate
    optimizemigration
    sendtestemail
    shell
    showmigrations
    sqlflush
    sqlmigrate
    sqlsequencereset
    squashmigrations
    startapp
    startproject
    test
    testserver

[sessions]
    clearsessions

[staticfiles]
    collectstatic
    findstatic
    runserver


Dentro de la carpeta del proyecto creada tenemos otros archivos que son:

__init__.py 

Es un archivo necesario para que Python trate el directorio del proyecto - Proyecto1 en el ejemplo - como un paquete.

settings.py 

Contiene, como te puedes imaginar por el nombre, todas las configuraciones de nuestro proyecto de Django.

urls.py

Es donde se almacenan las urls o direcciones de nuestro proyecto.

wsgi.py

Es el servidor web que vamos a utilizat en el proyecto de Django.


3) Creación de la Base de Datos del Proyecto.


Para que el proyecto se ponga en funcionamiento tenemos que crear una base de datos. Por defecto Django utiliza Sqlite3, aunque como veremos más tarde también soporta oficialmente PostgreSql, MySql o Oracle. Con desarrollos de terceros también es posible utilizar Sql server, Sap Sql, db2, Firebird etc.

Para empezar vamos a crear la que se utiliza por defecto Sqlite3, con el siguiente comando:

$ python manage.py migrate

>>> (miEntorno) chema@lenovo:~/Cursos/DJANGO$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK


Dentro de la carpeta Principal se habrá generado un archivo db.sqlite3.

base de datos sqlite3


El proyecto ya está listo para funcionar. Para ver que todo va bien tenemos que ejecutar un servidor web y usar el navegador para ver la página de bienvenida de Django. El servidor web que viene con Django es útil para probar nuestro proyecto pero NO para ponerlo en producción, sirve para ver si nuestros proyectos funcionan y se ven.


$ python manage.py runserver


>>> (miEntorno) chema@lenovo:~/Cursos/DJANGO$ python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
November 09, 2022 - 17:13:08
Django version 4.1.3, using settings 'proyecto1.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Ahora si abres el navegador web que utilices y vas a la dirección:


http://127.0.0.1:8000/

o

http://localhost:8000/

podrás ver, si esta todo instalado correctamente la página de bienvenida de Django:

Pagina de instalación correcta de Django

Vamos a personalizar algunos elementos de Django como son la hora local y el idioma. Por defecto la aplicación utiliza por defecto el idioma ingles y como hora local UTC (Coordinated Universal Time) que en verano es dos horas menos que la nuestra. (si estás en España)

Para cambiarlo busca el archivo settings.py y busca los siguientes valores:

...
# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True
...

Puedes usar el idioma y tu hora local, pero si quieres usar el Castellano y poner la hora de España cambia los siguientes valores:

LANGUAGE_CODE = 'es-es'

TIME_ZONE = 'Europe/Madrid'

4) Creación de una página web sencilla "Hola Mundo".

Lo primero que tenemos que hacer es crear un archivo nuevo que va a almacenar las diferentes vistas que vayamos almacenando. Este archivo, por convención, se suele llamar views.py. Estará dentro de la carpeta que contiene los demás, donde está el __init__.py.

Lo primero que tenemos que hacer es importar:

views.py

# Importar el módulo
from django.http import HttpResponse

# El nombre de la primera vista será Saludo
def saludo(request):
    return HttpResponse("Hola Mundo")

A cada función que creemos dentro de views.py se le denomina vista.

Ahora debemos decirle a Python cual es la Url que debemos introducir en el navegador para que nos de esta vista.

Esto se lo decimos en el archivo urls.py. En el mismo, al abrirlo, ya vienen las instrucciones de como construirla. Tiene que tener la siguiente estructura:

path("nombreurl/", nombre_de_la_vista)

nombreurl/ -> podemos poner el que nosotros queramos, pero por coherencia debería coincidir con el nombre de la función. (Hay que poner la barra al final).

nombre de la vista -> el mismo que pusimos en el archivo views.py

y como la función está en un archivo diferente al que nos encontramos hay que importarla:

from nombre_proyecto.views import nombre_de_la_vista

nombre_proyecto será el nombre de la carpeta que lo contiene:

En mi ejemplo: (en negrita está lo que se ha añadido de nuevo al archivo)

from django.contrib import admin
from django.urls import path
from Proyecto1.views import saludo

urlpatterns = [
    path('admin/', admin.site.urls),
    path('saludo/', saludo),
]

Si ejecutamos de nuevo el servidor de Django:

$ python manage.py runserver

y vamos a la siguiente Url: localhost:8000/saludo/

debemos ver lo siguiente:

hola mundo en Django

Próximo Post. 2.- Contenido dinámico e introducción de parámetros en url.

lunes, 7 de noviembre de 2022

Creación de Ejecutables de una aplicación en Python.

El ejecutable tomará la forma del sistema operativo con el que estemos trabajando. Si lo estas haciendo en Windows será un archivo con terminación .exe, si estas en Linux un archivo ejecutable sin terminación o con terminación .tar.gz y .dmg si estás en Mac.

Para crear el ejecutable voy a utilizar el siguiente código:

https://github.com/chema-hg/SISTEMA_SOLAR

Es una simulación del sistema solar que utiliza la biblioteca Pygame para funcionar, con lo que si no la tienes instalada deberías instalarla previamente. Yo creare un directorio, crearé en el un entorno virtual. Después copiaré aquí el programa, activaré el entorno virtual e instalaré en el la librería Pygame.

Vamos a utilizar para crear el ejecutable la biblioteca Pyinstaller.  Por tanto hay que instalarlo. Existen otros programas similares como, Py2exe, cx_Freeze. Para Mac también está py2app.

Lo primero comentar que si quieres crear un ejecutable para Windows tienes que instalarlo y usarlo en Windows y lo mismo para Linux o Mac, ya que este programa en concreto no compila la versión para otra plataforma. Yo estoy trabajando en Linux así que crearé un ejecutable para Linux.


>>> mkdir Ejecutable
>>> cd Ejecutable/ # Aquí, copia dentro de este directorio la aplicación.
>>> python3 -m venv Mientorno
>>> source ./Mientorno/bin/activate
(Mientorno) >>> pip install pygame
Collecting pygame
  Using cached pygame-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (21.9 MB)
Installing collected packages: pygame
Successfully installed pygame-2.1.2

(Mientorno) >>> pip install pyinstaller
Collecting pyinstaller
  Downloading pyinstaller-5.6.2-py3-none-manylinux2014_x86_64.whl (594 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 594.9/594.9 KB 3.5 MB/s eta 0:00:00
Collecting pyinstaller-hooks-contrib>=2021.4
  Downloading pyinstaller_hooks_contrib-2022.12-py2.py3-none-any.whl (250 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 250.0/250.0 KB 25.5 MB/s eta 0:00:00
Collecting altgraph
  Downloading altgraph-0.17.3-py2.py3-none-any.whl (21 kB)
Requirement already satisfied: setuptools in ./Mientorno/lib/python3.10/site-packages (from pyinstaller) (59.6.0)
Installing collected packages: altgraph, pyinstaller-hooks-contrib, pyinstaller
Successfully installed altgraph-0.17.3 pyinstaller-5.6.2 pyinstaller-hooks-contrib-2022.12

Una vez instalado lo primero que tenemos que hacer es ir al directorio donde tenemos la aplicación, que en este caso es el mismo, puesto que hemos copiado la aplicación app.py aquí.


 pyinstaller aplicación.py --onefile --windowed --icon=./logo.ico



La estructura del comando es la anterior, pero en este ejemplo no voy a usar icono.

(Mientorno) >>> pyinstaller app.py --onefile --windowed

app.py es el nombre del archivo que quieres convertir en un ejecutable.


Opciones:

--windowed es para que no aparezca la consola al ejecutar el programa. En mi caso no aparecerá la ventana de la consola (si el programa no tiene salida por terminal) y solamente el gui gráfico.

--onefile Para que se cree un solo archivo compilado con todo lo que la aplicación necesita. Se podrá ejecutar incluso en un ordenador que no tenga Python instalado. Si no lo incluyes te aparecerá un montón de archivos con todo lo necesario para que la aplicación funcione. Si lo haces solo aparecerá un archivo.

--icon. Más que nada en windows para que el ejecutable aparezca con el icono que le pongas. Eso si, tiene que ser un archivo ico.

Después de unas cuantas operaciones, al final el programa te dirá si se ha podido crear el ejecutable con éxito. El archivo o archivos del ejecutable ya compilado lo puedes encontrar en la carpeta "dist" que habrá creado el programa. Y solo queda ejecutarlo para ver que funcione.