miércoles, 22 de marzo de 2023

14.- Creación del primer servicio. Subir y Visualizar una imagen en la base de datos.

La aplicación que vamos a crear, la vamos a registrar también en el panel de administración para poder actualizar los datos o servicios desde el propio panel de administración. ¿Para que sirve esto?, pues por ejemplo si tenemos un restaurante, el propietario podrá subir el menú de cada día a través del panel de administración sin tener que modificar el código de las páginas web o mandárselo hacer al programador. 

Empezaremos creando una nueva aplicación para la zona de servicios de nuestro proyecto. En vez de elaborar una plantilla para la URL de servicios vamos a crear una nueva aplicación. Recordar que tenemos un Proyecto llamado "PracticaDjango" donde ya tenemos una aplicación llamada "Proyecto_web_app" y donde crearemos una segunda app para la zona de servicios llamada "Servicios".

Creemos, pues, la nueva aplicación:

$ python manage.py startapp Servicios
esquema directorios de las aplicaciones


Lo siguiente que tenemos que hacer es registrar esta nueva aplicación dentro del archivo settings.py de nuestro proyecto, dentro de nuestras aplicaciones.

PracticaDjango/PracticaDjango/settings.py

...
INSTALLED_APPS = [
    # Mis aplicaciones.
    'Proyecto_web_app',
    'Servicios',
    # Aplicaciones de terceros.
    'bootstrap5',
    # Aplicaciones por defecto de Django
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',      
]
...
Tenemos ahora que registrar en la base de datos de Django todas las características que tendrán esos servicios (titulo, contenido, imagen etc). Para esto tenemos que crear un modelo. Iremos al directorio de nuestra nueva aplicación 'Servicios' y entramos en el archivo models.py. Crearemos una clase que recoja los datos de esos servicios de la siguiente forma:

PracticaDjango/Servicios/models.py

from django.db import models

# Create your models here.
class Servicio(models.Model):
    titulo = models.CharField(max_length=50)
    # Django permite especificar el tamaño máximo del campo - max_length
    contenido = models.CharField(max_length=50)
    imagen = models.ImageField()
    # Para que automaticamente actualice las fechas usamos el argumento:
    # auto_now_add = True para guardar la fecha cuando se cree el registro.
    created = models.DateTimeField(auto_now_add=True)
    # auto_now = True para cuando se guarde o actualice el registro.
    updated = models.DateTimeField(auto_now=True)
    # Model meta Options - https://docs.djangoproject.com/en/4.1/topics/db/models/#meta-options
    class Meta:
        verbose_name = 'servicio ofrecido'
        verbose_name_plural = 'servicios ofrecidos'
        # Se utilizan para personalizar el nombre del modelo que se muestra
        # en el panel de administración.
    
    def __str__(self):
        # Para que nos devuelva el título del servicio.
        return self.titulo
A parte de los campos titulo, contenido e imagen puedes ver que hay otros dos campos que se suelen incluir y que se usan mucho en Django porque después son muy útiles para ordenar por fecha de creación y actualización. (created y updated)

También vamos a usar la clase Meta para poder usar verbose_name y verbose_name_plural. Los nombres que hemos especificado se usarán o serán los que aparezcan en el panel de administración de Django. En vez de usar el nombre que especificamos para la clase "Servicio", se usará el verbose_name de ese modelo para crear mensajes que sean menos "mecánicos". Y lo mismo para el plural de ese nombre. 

Antes de ejecutar las instrucciones que crearán la base de datos, como vamos a usar un campo que contendrá imágenes, es necesario instalar la librería Pillow que nos sirve para manipular imágenes.
$ pip install Pillow

Y como hemos visto ya, siempre que se crea o modifica un modelo hay que ejecutar las siguientes instrucciones:
$ python manage.py makemigrations
$ python manage.py migrate
Y con estos ya esta creada la tabla en la base de datos de nuestro proyecto. 

Para poder acceder al panel de administración si no lo hemos hecho ya antes tenemos que crear un superusuario. Esto se realiza con la instrucción:
$ python manage.py createsuperuser
A continuación tenemos que ir al archivo admin.py de la aplicación y registrarla. De la clase que acabamos de crear tenemos que importar su clase. Como esta en el mismo directorio usaremos el punto para importar la clase:

PracticaDjango/Servicios/admin.py

from django.contrib import admin
from .models import Servicio

# Register your models here.
# antes de registrar el servicio ponemos lo siguiente
# para que aparezcan los campos created y updated que por defecto
# no son visibles.
class ServicioAdmin(admin.ModelAdmin):
    readonly_fields = ('created', 'updated')

admin.site.register(Servicio, ServicioAdmin)

Si ejecutamos el servidor y accedemos a la URL admin  y dentro de servicios ofrecidos pulsamos en +Add veremos la siguiente imagen:


panel de administrador para crear servicios



Y ya dentro del panel de administración podemos crear el primer servicio que ofrezca nuestra empresa, con su titulo, contenido y una imagen. Los campos created y updated se pondrán automáticamente al pulsar el botón SAVE. 

Antes de continuar si queremos cambiar el idioma del panel de administración, al español por ejemplo, tenemos que ir al archivo settings.py del proyecto y buscar el apartado LANGUAGE_CODE y cambiarlo.

PracticaDjango/PracticaDjango/settings.py

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

#LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'es-eu'
...

Hecho este inciso, volvemos a donde lo dejamos y vamos a agregar un primer servicio desde el panel de administración. Como es nuestro primer servicio vamos a crear uno de ejemplo:

creando un primer servicio


Si todo ha ido bien en la parte superior saldrá un mensaje de que el "servicio fue creado correctamente".

Y si entramos en el servicio creado podemos ver la siguiente pantalla.

servicio creado pero que no carga la imagen

El PROBLEMA radica en que si pulsas sobre el archivo de la imagen nos mostrará un error que básicamente lo que nos dice es que no se encuentra la imagen. Lo que esta ocurriendo es que Django por defecto no está preparado para mostrar contenido multimedia en modo de desarrollo. Tendremos que modificar su configuración para conseguirlo.

Además si miras el directorio del proyecto verás que la imagen subida Django la pone en la raiz del directorio lo cual no es muy práctico para tener el proyecto ordenado.

Vamos a ordenarlo todo un poco. En la raíz del proyecto crearemos una carpeta llamada 'media'. Y ahora tenemos que decirle a Django que busque los archivos multimedia en esta carpeta en concreto. Esto lo hacemos desde el archivo settings.py. Iremos al final del archivo e incluiremos las siguientes instrucciones:

PracticaDjango/PracticaDjango/settings.py

...
# Para poder ver y organizar el contenido multimedia que no es propiamente de la página
# Url pública de las imágenes, video, etc. que aparecerá en la barra del navegador
MEDIA_URL = 'media/'
# Donde debe buscar las imágenes, sonidos, videos etc.
MEDIA_ROOT = BASE_DIR/'media'

Esto permitirá a Django administrar la carga de archivos y servir archivos multimedia. MEDIA_URL es la URL base utilizada para servir los archivos multimedia cargados por los usuarios. MEDIA_ROOT es la ruta local donde residen. Los directorios y Las URL de los archivos se crean dinámicamente anteponiendo la ruta del proyecto o la URL del medio.

Con MEDIA_URL ='media/' queremos decir que la URL pública para nuestros archivos media será la que hemos definido 'media/'. Y una vez que tenemos definida esa URL pública, con MEDIA_ROOT = BASE_DIR/'media' le decimos donde tiene que buscarlo localmente.

Dentro de la carpeta media, para tenerlo todo más ordenado, deberíamos tener una jerarquía de subcarpetas para guardar los archivos media de cada una de las aplicaciones que vamos creando. Recuerda que hasta ahora tenemos dos creadas "Proyecto_web_app" y "Servicios".

 Lo ideal es que al registrar en la base de datos cada nuevo servicio, estos archivos se subieran automáticamente a la subcarpeta correspondiente. Y esto ¿Cómo lo conseguimos? Pues nos tenemos que ir al archivo models.py de la aplicación que queramos, en este caso de la aplicación 'Servicios' y simplemente en el campo de la base de datos donde configuramos el campo "ImageField" añadimos la opción "upload_to" y el nombre del subdirectorio correspondiente que queramos, que creará automáticamente Django dentro del directorio 'media' que se encuentra en la raiz del proyecto,  y hecho esto cuando registremos la imagen se guardará en este subdirectorio dentro de 'media' como ya he dicho, sin que nosotros tengamos que crear el subdirectorio.


PracticaDjango/Servicios/models.py

class Servicio(models.Model):
    titulo = models.CharField(max_length=50)
    # Django obliga a especificar el tamaño maximo del campo - max_length
    contenido = models.CharField(max_length=50)
    imagen = models.ImageField(upload_to = 'Servicios')
    # Para que automaticamente actualice las fechas usamos el argumento
    # auto_now_add = True
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now_add=True)
La estructura del directorio quedaría algo tal que así, después de subir la imagen.

directorio del programa de Django

Ya solo nos falta registrar la URL pública que hemos creado, en archivo URLS.py del proyecto, para que la tenga como URL de búsqueda.

Vamos a importar el archivo 'settings' para tener disponible tanto 'MEDIA_URL' y 'MEDIA_ROOT' y también tendremos que importar los archivos 'static'. Después de hecho esto solo nos queda agregar a URL_PATTERS la nueva URL de estos archivos estáticos:

PracticaDjango/PracticaDjango/urls.py

from django.contrib import admin
from django.urls import path, include
# Para registrar los archivos de las imagenes y poder verlas
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('Proyecto_web_app.urls'))
]
if settings.DEBUG:
    urlpatterns+=static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Hemos añadido el condicional a la función para servir archivos multimedia con el servidor de desarrollo de Django cuando estamos en modo de desarrollo.

Esta función condicional está disponible para desarrollo, pero NO DEBEMOS
USARLA EN PRODUCCIÓN. Django es muy ineficiente sirviendo archivos
estáticos. NUNCA sirvas tus archivos con Django en un entorno de Pro-
ducción. Aprenderemos como servir archivos estáticos en entornos de 
Producción más adelante.

y ahora si. Borramos el registro de prueba que habíamos creado. Lo volvemos a crear de nuevo. La imagen ahora estará en /media/Servicios. Si vamos de nuevo al panel de administración, pinchamos en 'Servicios Ofrecidos' y pinchamos en la imagen, Django nos la mostrará correctamente.

Ahora que Django nos muestra correctamente las imágenes, vamos a ver como mostrar toda esa información en la página de servicios que habiamos creado

Lo primero que tenemos que hacer es ir al archivo views.py de la aplicación que muestra las páginas de nuestra aplicación "Proyecto_web_app" y localizar la vista dedicada a los servicios. Lo único que hace esta vista es un renderizado de la plantilla servicios. Pero como ahora le vamos a pasar los servicios que hemos registrado en la base de datos, tenemos que importarlos primero y después decirle a nuestra vista de servicios que los muestre en esa plantilla, uno debajo de otro.

PracticaDjango/Proyecto_web_app/views.py

from django.shortcuts import render, HttpResponse
# Para cargar los servicios y mostrarlos en la página web
from Servicios.models import Servicio

# Create your views here.

def home(request):
    return render(request, 'Proyecto_web_app/inicio.html')

def servicios(request):
    # Para importar todos los servicios que creamos en el panel de admon.
    datos = Servicio.objects.all()
    return render(request, 'Proyecto_web_app/servicios.html', {'servicios': datos})

...
Después iremos a nuestro template y tendremos que decirle que nos muestre todos los servicios que hemos creado. Esto lo haremos recorriéndolos con un bucle for.

PracticaDjango/Proyecto_web_app/templates/Proyecto_web_app/servicios.html

<!--Cargamos la plantilla base-->
{% extends "Proyecto_web_app/base.html" %}

<!--Cargamos el contenido estático-->
{% load static %}

<!-- Establecemos el titulo de la página -->
{% block title %}Servicios{% endblock %}

<!-- Definimos su contenido -->
{% block content %}
    <h2>Esta es la página de SERVICIOS.</h2>
    <!--Para recorrer los servicios que vayamos creando-->
{% for servicio in servicios %}
<div>
    <p>
        <h2>{{servicio.titulo}}</h2>
        <p>{{servicio.contenido}}</p>
        <p>
            <img src="{{servicio.imagen.url}}">
        </p>
    </p>
</div>
{% endfor %}

{% endblock %}
y con esto si iniciamos el servidor y entramos en la url de servicios desde el navegador web ya nos tendría que mostrar los servicios ofrecidos.





miércoles, 1 de marzo de 2023

13.- Desarrollo práctico de una aplicación. Herencia Plantillas, Css y Bootstrap.

Formatear el sitio web con bootstrap.

Es un framework css que nos sirve para formatear un sitio web entero utilizando css. Es 'responsive' ya que nos sirve para que se vea bien en cualquier tipo de dispositivo y además es prácticamente compatible con todos los navegadores.

Volviendo a nuestro proyecto lo que perseguimos es dar a la página web un formato general para lo cual utilizaremos Bootstrap y también herencia de plantillas. Así conseguiremos que todas las páginas tengan unas zonas comunes y otras zonas específicas donde cargaremos el contenido correspondiente a cada página. En definitiva lo que queremos conseguir es mejorar la apariencia.

Link a bootstrap.

Para utilizar Bootstrap hay dos caminos:

1.- Linkar con los contenidos o librerías de Bootstrap de forma externa. 

2.- Descargarnos los contenidos para utilizarlo en local. En este caso utilizaremos django-bootstrap5 para integrar BootStrap en nuestro proyecto. Esta aplicación descarga los archivos que necesitaremos de Bootstrap, los coloca en los lugares apropiados dentro de nuestro proyecto y hace que las plantillas de estilo estén disponibles para uso. 

Para instalar Django-Bootstrap5 ejecutaremos la siguiente instrucción. Como comente al inicio del curso yo recomiendo hacerlo todo dentro de un entorno virtual. Se puede instalar a través de dos paquetes distintos. Elige uno u otro.

(entorno_virtual) $ pip install django-bootstrap5

* con este paquete tendrás que registrar la aplicación en settings 
  como 'django_bootstrap5'

o

(entorno_virtual) $ pip install django-bootstrap-v5

* con este paquete tendrás que registrar la aplicación en settings
  como 'bootstrap5'


A continuación tenemos que añadir el siguiente código para incluir Django-Bootstrap5 dentro de INSTALLED_APPS en el archivo settings.py del proyecto. Como he instalado el segundo paquete la registraré de la siguiente forma.


PracticaDjango/PracticaDjango/settings.py

INSTALLED_APPS = [
    # Mis aplicaciones.
    'Proyecto_web_app',
    # Aplicaciones de terceros.
    'bootstrap5',
    # Aplicaciones por defecto de Django
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',      
]

Asegúrate de que colocar esta aplicación 'bootstrap5' después de mis aplicaciones pero antes de las aplicaciones por defecto de Django.

A continuación vamos a ir al directorio de nuestra aplicación y crearemos una carpeta llamada static. Dentro de esta, crearemos otra con el nombre de la aplicación. Aquí irá todo el contenido estático, ya sean imágenes o código CSS. Su contenido no dependerá del contexto de la petición y será el mismo para todos los usuarios. Dentro de esta crearemos otras dos carpetas de momento. Una llamada css que como su nombre indica recogerá el código css de la aplicación y otra img donde guardaremos las imágenes que puedan utilizar las plantillas.

La estructura del directorio sería la siguiente:

/PracticaDjango -> 

    /Proyecto_web_app ->

       /static ->

                /Proyecto_web_app ->

                        /css

                        /img

Lo primero que tenemos que hacer es crear una plantilla que será el modelo para todas las demás plantillas que podamos crear. Se llamará base.html y de esta heredarán todas las demás. Como vamos a necesitar una barra de navegación crearé una muy sencilla que luego usare en la plantilla base. 

PracticaDjango/Proyecto_web_app/templates/Proyecto_web_app/nav.html

<nav>
    <ul>
        <li><a href="#">Home</a></li>
        <li><a href="#">Servicios</a></li>
        <li><a href="#">Blog</a></li>
        <li><a href="#">Tienda</a></li>
        <li><a href="#">Contacto</a></li>
    </ul>
</nav>

Y este sería el código de la plantilla base "base.html"

PracticaDjango/Proyecto_web_app/templates/Proyecto_web_app/base.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>Página en Prueba</title>
</head>
<body>
    <header>
        <h1>UnikGAME TIENDA VIRTUAL</h1>
        <hr>
        <p>Barra de navegación insertada</p>
        {% include "Proyecto_web_app/nav.html" %}
    </header>
    <section>
        <p>Aquí irá la parte cambiante de la página</p>
    </section>
    <footer>
        <hr>
        <small>Politica de Privacidad . Aviso Legal . Cookies</small>
    </footer>
</body>
</html>


Herencia de Plantillas


La plantilla base.html va a ser nuestra plantilla madre. La vamos a utilizar para modificar las cinco plantillas hijas, que heredarán los elementos comunes de esta (header, barra de navegación y footer), y que se corresponderán con cada una de las páginas de nuestro sitio web. (Home, Servicios, Blog, Tienda y Contacto). Sin embargo, ten en cuenta que si una plantilla hija tiene algún elemento que también este definido en la plantilla padre, los elementos de esta última prevalecerán sobre las de la plantilla padre. 

Por ejemplo, en la plantilla padre has definido un determinado footer y en la hija otro distinto, el footer de la plantilla hija prevalece sobre la de la padre. No habrá herencia.

Empecemos modificando la plantilla base.html que ya tenemos para indicar las partes o bloques que las otras plantillas pueden escribir. Si tuviéramos hoja de estilos tendríamos que definirlas aquí. En este fichero incluiremos los bloques:

{% block title %} {% endblock %}
{% block content %} {% endblock %}

para definir el titulo y el contenido de las páginas hijas.

PracticaDjango/Proyecto_web_app/templates/Proyecto_web_app/base.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>{% block title %}{% endblock %}</title>
</head>
<body>
    <header>
        <h1>UnikGAME TIENDA VIRTUAL</h1>
        <hr>
        <p>Barra de navegación insertada</p>
        {% include "Proyecto_web_app/nav.html" %}
    </header>
    <section>
        {% block content %}{% endblock %}
    </section>
    <footer>
        <hr>
        <small>Politica de Privacidad . Aviso Legal . Cookies</small>
    </footer>
</body>
</html>


Y AHORA VIENE LA GRACIA DEL ASUNTO....

Si te fijas la plantilla padre, base.html, tiene 24 líneas de código y sin contar las de la barra de navegación que están aparte en el archivo nav.html. Pues bien, si no usáramos herencia, tendríamos que copiar todo esto en cada una de las páginas que diseñemos, junto con las modificaciones necesarias para que mostrarán lo que queremos que aparezcan en cada una de ellas. Sin embargo usando la herencia:

PracticaDjango/Proyecto_web_app/templates/Proyecto_web_app/inicio.html

<!--Cargamos la plantilla base-->
{% extends "Proyecto_web_app/base.html" %}

<!-- Establecemos el titulo de la página -->
{% block title %}Home{% endblock %}

<!-- Definimos su contenido -->
{% block content %}
    <h2>Esta es la página de Inicio.</h2>
{% endblock %}
Esta primera plantilla hija la comenzamos diciendo que use la plantilla padre con la instrucción:

{% extends "Proyecto_web_app/base.html" %}

Para continuar reescribiendo los dos bloques, con lo que estamos diciendo al programa que busque estos bloques en la plantilla padre y que los sustituya por los que hemos puesto en esta plantilla.

El primero {% block title %} {% endblock %} modifica el título de la vista de inicio (HOME).

El segundo {% block content %} {% endblock %} mostrará el contenido propio de la página de inicio.

Este es el resultado.

Renderizado Página Home


Tenemos que modificar el resto de las cuatro plantillas exactamente de la misma forma. Una vez hecho lo anterior modificaremos el archivo nav.html que contiene el menú de navegación. Tiene que recoger la dirección de cada una de las páginas. Para obtener la URL de una vista en Django, podemos usar el siguiente código:

<a href="{% url 'nombre_de_la_vista' parámetros %}">Link a la vista</a>

donde el 'nombre_de_la_vista' vendrá definido como:

app_name:name  


Para ver de donde sale esto vamos a ir al archivo urls.py de nuestra aplicación Proyecto_web_app.


from django.urls import path
from . import views

app_name  = 'Proyecto_web_app'

urlpatterns = [
    path('', views.home, name='home'),
    path('servicios/', views.servicios, name='servicios'),
    path('tienda/', views.tienda, name='tienda'),
    path('blog/', views.blog, name='blog'),
    path('contacto/', views.contacto, name='contacto'),

]

Por ejemplo en mi ordenador al ejecutar el servidor, la dirección para la página de la tienda es:

http://127.0.0.1:8000/tienda/

Pues bien, al usar {% url 'Proyecto_web_app:tienda' %}, esta ya se construye automáticamente. Esto tiene la gran ventaja que si mas tarde queremos cambiar la url de alguna de las páginas no tendremos que tocar este archivo puesto que se construirán automáticamente.

Dicho lo cual el archivo nav.html quedaría de la siguiente forma.


PracticaDjango/Proyecto_web_app/templates/Proyecto_web_app/base.html

<nav>
    <ul>
        <li><a href="{% url 'Proyecto_web_app:home' %}">Home</a></li>
        <li><a href="{% url 'Proyecto_web_app:servicios' %}">Servicios</a></li>
        <li><a href="{% url 'Proyecto_web_app:blog' %}">Blog</a></li>
        <li><a href="{% url 'Proyecto_web_app:tienda' %}">Tienda</a></li>
        <li><a href="{% url 'Proyecto_web_app:contacto' %}">Contacto</a></li>
    </ul>
</nav>

También es posible pasar argumentos a la vista a través de la URL, agregando parámetros de la siguiente forma:

<a href="{% url 'nombre_de_la_vista' argumento1 argumento2 %}">Link a la vista con argumentos</a>


Dando formato a las plantillas con CSS y BootStrap.


Aunque el Css lo podemos aplicar tanto desde la propia etiqueta de HTML, como dentro del archivo HTML, lo normal es que construyas la hoja de estilo en un archivo externo ya que de esta forma te vale para todas las páginas html que crees, básicamente entre otras muchas ventajas.

Si construimos nosotros mismos las hojas de estilo, por ejemplo en un archivo llamado styles.css, tenemos que guardarlo, como ya vimos, dentro de una carpeta llamada "static". En Django esa carpeta "static" va a recoger todo lo relativo a contenido estático del proyecto (css, javascript, imagenes, pdf etc)

Mi archivo de ejemplo se encontrará en el siguiente directorio:

PracticaDjango / Proyecto_web_app/ static / Proyecto_web_app / css / styles.css

Y para cargarlo tendremos que utilizar la siguiente instrucción dentro de las etiquetas <head> de  la página HTML que queramos aplicarlo. 

                    {% load static %}

                    <link rel="stylesheet" href="{% static 'Proyecto_web_app/css/styles.css' %}">

Ahora bien, en vez de hacerlo tu mismo puedes utilizar el framework Bootstrap. Bootstrap te permite crear interfaces web con CSS y Javascript, visualmente más agradables, con elementos que ya están prediseñados y que además se adaptan al tamaño del dispositivo en el que se visualicen. Para poder usarlo tenemos que iniciar el archivo base.html con:

                    {% load bootstrap5 %}

* o {% load django_bootstrap5 %} dependiendo del paquete utilizado.

y dentro de la etiqueta <head> usar el cargador:

                    {% bootstrap_css %} para usar las clases de bootstrap

                    {% bootstrap_javascript %} para usar java

                    {% bootstrap_messages %} para usar las alertas de Django.

De esta forma la cabecera del archivo base.html quedaría de la siguiente forma:

PracticaDjango/Proyecto_web_app/templates/Proyecto_web_app/base.html

{% load bootstrap5%}
{% load static %}
<!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>{% block title %}{% endblock %}</title>
    
    <!-- Add Bootstrap CSS -->
    {% bootstrap_css %}
    {% bootstrap_javascript %}
    {% bootstrap_messages %}
<!-- Add additional CSS in static file --> <link rel="stylesheet" href="{% static 'Proyecto_web_app/css/styles.css' %}"> </head> ...

Rediseño del Header y de la barra de navegación.


Comenzamos con el header de la plantilla base.html.

PracticaDjango/Proyecto_web_app/templates/Proyecto_web_app/base.html

<header>
        <h1 class="container-fluid text-center text-white bg-dark py-5">
            UnikGAME
        </h1>
        {% include "Proyecto_web_app/nav.html" %}        
</header>
 A la etiqueta <h1> le aplicamos la clase "container-fluid" que es es un contenedor que ocupa todo el ancho de la ventana. También centramos el texto con text-center, le aplicamos un color blanco (text-white) y un fondo oscuro al contenedor con bg-dark. Para que el texto este centrado le aplicamos un padding tanto arriba como abajo de nivel 5. (py-5). Puedes encontrar información sobre estos elementos aquí.

Como incluimos la barra de navegación a través del archivo nav.htlm vamos a modificar el mismo.  Dentro de la documentación de Bootstrap si entramos en la sección de documentación y bajamos a Components encontramos ejemplos de muchos elementos. Dentro de estos, esta Navs&tabs donde tenemos un ejemplo sencillo de barra de navegación que vamos a aplicar.

PracticaDjango/Proyecto_web_app/templates/Proyecto_web_app/nav.html

<ul class="nav justify-content-center my-2">

  <li class="nav-item px-lg-4">
    <a class="nav-link text-uppercase text-expanded" href="{% url 'Proyecto_web_app:home' %}">
    Home
    </a>
  </li>

  <li class="nav-item px-lg-4">
    <a class="nav-link text-uppercase text-expanded" href="{% url 'Proyecto_web_app:servicios' %}">
    Servicios
    </a>
  </li>

  <li class="nav-item px-lg-4">
    <a class="nav-link text-uppercase text-expanded" href="{% url 'Proyecto_web_app:blog' %}">
    Blog
    </a>
  </li>

  <li class="nav-item px-lg-4">
    <a class="nav-link text-uppercase text-expanded" href="{% url 'Proyecto_web_app:tienda' %}">
    Tienda
    </a>

  </li>
  <li class="nav-item px-lg-4">
    <a class="nav-link text-uppercase text-expanded" href="{% url 'Proyecto_web_app:contacto' %}">
    Contacto
    </a>
  </li>
  
</ul>


Con estos pocos cambios conseguimos que la base de las plantillas tenga ahora este aspecto.

sección header modificada con bootstrap

Para acabar de mejorar el diseño añadiremos un fondo a la página. 

PracticaDjango/Proyecto_web_app/templates/Proyecto_web_app/base.html

...
    <!-- Parte cambiante de las plantillas -->
    <div class="fondo">
    <section>
        {% block content %}{% endblock %}
    </section>
    </div>
...

PracticaDjango/Proyecto_web_app/static/Proyecto_web_app/css/styles.css

.fondo {
    background-image: url(../img/bg_main.jpg);
    height: 58vh;
    background-position: center;
    background-repeat: no-repeat;
    background-size: cover;
}
Retocaremos un poco tambien el footer:
... 
<div class="fondo">
        <section>
            {% block content%}{% endblock %}
        </section>
    </div>

    <footer class="footer bg-dark text-center text-white">
        <hr>
        <small>
            <a href="#">Política de privacidad</a> ·
            <a href="#">Aviso legal</a> ·
            <a href="#">Cookies</a>
        </small>
        <p class="py-2"><small>(c) UnikGAME 2023</small></p>
    </footer>
</body>
</html>

Quedaría una apariencia parecida a esta, común para todas las páginas.


pagina base finalizada


Parar finalizar vamos a añadir código para resaltar la página activa, cambiando el color azul del enlace por el negro.

{% if request.path == '/' %}text-black{% endif %}">

request.path nos dará la url de la página en la que nos encontramos. De esta forma si la url definida coincide con la que nos encontramos, se aplicará la clase text-black. El archivo nav.html quedaría de la siguiente forma:

PracticaDjango/Proyecto_web_app/templates/Proyecto_web_app/nav.html

<ul class="nav justify-content-center my-2">

    <li class="nav-item px-lg-4">
        {% url 'Proyecto_web_app:home' as home_url %}
        <a class="nav-link text-uppercase fw-bold text-expanded {% if request.path == home_url %}
        text-black{% endif %}" href="{{ home_url }}">Inicio</a>
    </li>

    <li class="nav-item px-lg-4">
        {% url 'Proyecto_web_app:servicios' as servicios_url %}
        <a class="nav-link text-uppercase fw-bold text-expanded {% if request.path == servicios_url %}
        text-black{% endif %}" href="{{ servicios_url }}">Servicios</a>
    </li>

    <li class="nav-item px-lg-4">
        {% url 'Proyecto_web_app:blog' as blog_url %}
        <a class="nav-link text-uppercase fw-bold text-expanded {% if request.path == blog_url %}
        text-black{% endif %}" href="{{ blog_url }}">Blog</a>
    </li>

    <li class="nav-item px-lg-4">
        {% url 'Proyecto_web_app:tienda' as tienda_url %}
        <a class="nav-link text-uppercase fw-bold text-expanded {% if request.path == tienda_url %}
        text-black{% endif %}" href="{{ tienda_url }}">Tienda</a>
    </li>

    <li class="nav-item px-lg-4">
        {% url 'Proyecto_web_app:contacto' as contacto_url %}
        <a class="nav-link text-uppercase fw-bold text-expanded {% if request.path == contacto_url %}
        text-black{% endif %}" href="{{ contacto_url }}">Contacto</a>
    </li>
</ul>

1. `<ul class="nav justify-content-center my-2">`: Esto define una lista no ordenada (ul) con algunas clases de Bootstrap, como "nav" y "justify-content-center", para crear una barra de navegación centrada en la página.

2. Cada elemento de la lista (li) representa un enlace en la barra de navegación.

3. `{% url 'Proyecto_web_app:nombre_de_la_vista' as nombre_de_url %}`: Estas líneas utilizan la plantilla de Django para generar la URL de una vista de Django y asignarla a una variable llamada "nombre_de_url." Esto permite que el código sea más limpio y evita repetir la generación de URLs en cada enlace.

4. `<a>`: Cada enlace (`<a>`) contiene clases de Bootstrap y utiliza la variable previamente definida, como `{{ home_url }}`, para definir el atributo "href" con la URL correspondiente a la vista.

5. `{% if request.path == nombre_de_url %}text-black{% endif %}`: Esta es una condición que verifica si la URL actual (`request.path`) coincide con la URL generada para el enlace (la variable "nombre_de_url"). Si es cierto, se agrega la clase "text-black" al enlace, lo que generalmente se utiliza para resaltar el enlace activo en la barra de navegación.


Si por ejemplo pinchamos en la página 'blog' la página web quedaría de la siguiente manera:

resaltando el enlace