viernes, 16 de junio de 2023

18.- Creación de la aplicación Tienda (menú de pestañas, tarjetas con Bootstrap5 y easy-thumbnails)

En este capítulo desarrollaremos parte de la aplicación Tienda. Aquí mostraremos los diferentes productos que pretendemos vender en ella. A través de un menú de pestañas mostraremos los diferentes juegos que tenemos para las diferentes plataformas. Luego mostraremos los juegos de cada plataforma a través de tarjetas ("cards") de bootstrap5, cuatro por cada fila. Quedará algo similar a esto:


ejemplo de tienda web

La creación de la aplicación es muy similar al resto que hemos visto hasta ahora:

1.- Creamos la nueva aplicación que gestionará la tienda.

$ python manage.py startapp Tienda

2.- Una vez creada la registramos:

PracticaDjango/PracticaDjango/settings.py

...
INSTALLED_APPS = [
    # Nuestras aplicaciones
    'Proyecto_web_app.apps.ProyectoWebAppConfig',
    'Servicios.apps.ServiciosConfig',
    'Blog.apps.BlogConfig',
    'Contacto.apps.ContactoConfig',
    'Tienda.apps.TiendaConfig',
    # Aplicaciones de terceros
    'django_bootstrap5',
    # Mapa del Sitio
    'django.contrib.sites', # add sites to installed_apps
    'django.contrib.sitemaps',  # add Django sitemaps to installed app
    # PostgreSQL
    'django.contrib.postgres',
    # Aplicaciones por defecto
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
...
Ahora lo que necesitamos es que cuando se vaya a la URL /tienda/, Django debe buscar la ruta en el archivo urls.py pero de la aplicación "Tienda", no en la del proyecto. Vamos a hacer las modificaciones necesarias.

Primeramente en el archivo:

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')),
    path('servicios/', include('Servicios.urls')),
    path('blog/', include('Blog.urls')),
    path('contacto/', include('Contacto.urls')),
    path('sitemap.xml', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap'),
    path('tienda/', include('Tienda.urls')),
]
urlpatterns+=static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
y luego en archivo que gestiona las urls de la tienda. Entra en el directorio de la aplicación Tienda, crea el archivo urls.py y añade el siguiente código:

PracticaDjango/Tienda/urls.py: 

from django.urls import path
# load views of these applications.
from . import views

app_name = 'Tienda'

urlpatterns = [
    path('', views.tienda, name='tienda'),
]

Más tarde crearemos la vista y la plantilla a renderizar. Pero antes vamos a preparar otras cosas.


Creación de modelos para el catálogo de productos.


3.- Como vamos a vender juegos de consola necesitamos definir dos cosas. Una categoría para registrar las diferentes consolas para las que vendemos los juegos y luego otra categoría para los propios juegos en si. Es decir, la categoría de las consolas será (ps4, ps5, xbox y nintendo)  y luego las categorías de los juegos tendrán sus propios campos como nombre del juego, categoría, que es la consola a la que pertenecen, una pequeña descripción, precio, si están disponibles en el stock de la tienda y una imagen. Los productos tendrán también un campo en el que se registrará la fecha en la que fue creada y la fecha en la que se actualiza. Para ello creamos el archivo models.py dentro de la aplicación Tienda y codificamos lo anterior de la siguiente forma:

PracticaDjango/Tienda/models.py: 

from django.db import models

# Create your models here.

# Creamos dos modelos para la categoría del producto (tipo de consola)
# y para el producto (el juego en si).

class CategoriaProducto(models.Model):
    '''Registrará las diferentes consolas para las que vendemos juegos'''
    nombre = models.CharField(max_length=200)
    slug = models.SlugField(max_length=200, unique=True)

    class Meta:
        ordering = ["nombre"]
        indexes = [
            models.Index(fields=["nombre"]),
        ]
        verbose_name = "categoriaProducto"
        verbose_name_plural = "categoriasProductos"

    def __str__(self):
        return self.nombre
    

class Producto(models.Model):
    """Registra los propios juegos en si."""

    nombre = models.CharField(max_length=200)
    slug = models.SlugField(max_length=200)
    categoria = models.ForeignKey(
        CategoriaProducto, on_delete=models.CASCADE, related_name="categoria_productos"
    )
    descripcion = models.CharField(blank=True)
    precio = models.DecimalField(max_digits=10, decimal_places=2)
    stock = models.BooleanField(default=True)
    # hay que tener instalado la libreria pillow para poder subir imagenes
    imagen = models.ImageField(upload_to="Tienda", blank=True)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["nombre"]
        indexes = [
            models.Index(fields=["id", "slug"]),
            models.Index(fields=["nombre"]),
            models.Index(fields=["-created"]),
        ]
        verbose_name = "producto"
        verbose_name_plural = "productos"

    def __str__(self):
        return self.nombre

Importante: Para trabajar con las imágenes de los juegos es absolutamente imprescindible que tengas instalada la librería Pillow.(pip install Pillow)

El catálogo de nuestra tienda consistirá en una serie de juegos que estarán organizados en diferentes categorías que serán los diferentes tipos de consolas. Cada juego tendrá su nombre, una descripción opcional, una imagen opcional, un precio y si existe disponibilidad o stock del mismo.

En el código superior hemos creado los modelos CategoríaProducto y Producto. El modelo de CategoríaProducto consta de un campo de nombre y un campo único de "slug" (único implica la creación de un índice). En la clase Meta del modelo de CategoríaProducto, hemos definido un índice para el campo de nombre.

Los campos del modelo de Producto son los siguientes:

• categoria: Una clave foránea (ForeignKey) al modelo de Categoría. Esta es una relación de uno a muchos: un producto pertenece a una categoría y una categoría contiene múltiples productos.
• nombre: El nombre del producto.
• slug: El "slug" para este producto para construir URLs bonitas.
• imagen: Una imagen opcional del producto.
• descripcion: Una descripción opcional del producto.
• precio: Este campo utiliza el tipo decimal.Decimal de Python para almacenar un número decimal de precisión fija. El número máximo de dígitos (incluyendo los lugares decimales) se establece utilizando el atributo max_digits y los lugares decimales con el atributo decimal_places.
• stock: Un valor booleano que indica si el producto está disponible o no. Se utilizará para habilitar/deshabilitar el producto en el catálogo.
• created: Este campo almacena cuándo se creó el objeto.
• updated: Este campo almacena cuándo se actualizó el objeto.

Para el campo de precio, usamos DecimalField en lugar de FloatField para evitar problemas de redondeo.

En la clase Meta del modelo de Producto, hemos definido un índice de múltiples campos para los campos id y slug. Ambos campos están indexados juntos para mejorar el rendimiento de las consultas que utilizan los dos campos.

Siempre utiliza DecimalField para almacenar cantidades monetarias. FloatField utiliza internamente el tipo float de Python, mientras que DecimalField utiliza el tipo Decimal de Python. Al usar el tipo Decimal, evitarás problemas de redondeo de los números flotantes.

Planeamos consultar productos en principio por su id aunque dejamos abierta la puerta para hacerlo con su "slug". Hemos añadido un índice para el campo de nombre y otro para el campo de creación. Hemos utilizado un guión antes del nombre del campo para definir el índice con un orden descendente.

Models for the product catalog



Registrando los modelos en el panel de administración.



4.- Puesto que tenemos que meter los tipos de consolas y los juegos de las diferentes plataformas, lo vamos a hacer a través del panel de Administración de Django, por lo cual creamos el correspondiente archivo admin.py dentro de la aplicación Tienda. Importamos los modelos que hemos creado y luego añadimos el siguiente código.

PracticaDjango/Tienda/admin.py: 

from django.contrib import admin

from .models import *

# Register your models here.

class CategoriaProductoAdmin(admin.ModelAdmin):
    list_display = ["nombre", "slug"]
    prepopulated_fields = {"slug": ("nombre",)}


class ProductoAdmin(admin.ModelAdmin):
    list_display = ["nombre", "slug", "precio", "stock", "created", "updated"]
    list_filter = ["stock", "created", "updated"]
    list_editable = ["precio", "stock"]
    prepopulated_fields = {"slug": ("nombre",)}

# Registramos ambas tablas y clases
admin.site.register(CategoriaProducto, CategoriaProductoAdmin)
admin.site.register(Producto, ProductoAdmin) 

Recuerda que se utiliza el atributo prepopulated_fields para especificar campos donde el valor se establece automáticamente usando el valor de otros campos. Como has visto anteriormente, esto es conveniente para generar "slugs".

Se usa el atributo list_editable en la clase ProductoAdmin para establecer los campos que se pueden editar desde la página de visualización de la lista del sitio de administración. Esto te permitirá editar múltiples filas a la vez.

Cualquier campo en list_editable también debe estar incluido en el atributo list_display, ya que solo los campos mostrados pueden ser editados.


Construyendo las vistas.


5.- Necesitamos crear el archivo de vistas que renderizará la plantilla y  los datos de la tienda. Para ello creamos el archivo views.py:

PracticaDjango/Tienda/views.py: 

from django.shortcuts import render

# Como trabajamos con productos vamos a importarlos
from Tienda.models import Producto

# Create your views here.

def tienda(request):
    productos = Producto.objects.filter(stock=True)
    # carga en la variable productos todos los juegos que hayamos introducido a través
    # del panel de administración de Django.
    contexto = {
        "productos": productos
    }
    
    return render(request, "Tienda/tienda.html", contexto)   
   


En el código anterior, hemos realizado la búsqueda con el filtro stock=True para devolver solamente los productos que estén disponibles.




Puesto que anteriormente hemos creado el archivo models.py y realizado modificaciones, antes de seguir adelante tenemos que realizar las migraciones. Para ello ejecuta en el shell de python las siguientes instrucciones:

python manage.py makemigrations

python manage.py migrate


Para luego probar que todo funciona aquí deberías parar un momento y entrar en el panel de administración de Django y poner algunos datos de consolas y juegos. Si quieres usar la plantilla html que voy a explicar luego tienes que crear cuatro tipos de consolas (PS4, PS5, XBOX y NINTENDO) dentro del apartado CategoriaProductos y luego al menos en una de las categorías poner cuatro juegos. (Dentro del campo Productos)


6.- Ahora viene lo más importante que es crear la plantilla tienda.html. No te asustes porque aunque es un poco larga, es muy sencilla de explicar e iremos paso a paso. Lo primero es crear el directorio templates/Tienda dentro de la aplicación Tienda. Luego creamos el archivo tienda.html. Pero antes de teclear código, tenemos que borrar todo lo que creamos al principio en la aplicación Proyecto_web_app y que hacia referencia a la tienda cuando teníamos la web en pruebas. Borraremos en urls.py la línea que hace referencia a el path de la tienda, en views.py la vista de la tienda, y en el template la plantilla tienda.html. Todo esto está dentro de Proyecto_web_app. Ahora introducimos el código html de la página de la tienda, ya en su aplicación correspondiente.


PracticaDjango/Tienda/templates/Tienda/tienda.html 

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

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

<!-- Definimos su contenido -->
{% block content %}
<h1 class="text-center">Elige tu Consola.</h1>

<div class="container">
  <div class="bg-dark">
    <ul class="nav nav-tabs">
      <li class="nav-item">
        <a class="nav-link active" id="ps4-tab" data-bs-toggle="tab" href="#ps4" role="tab" aria-controls="ps4"
          aria-selected="true">PS4</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" id="ps5-tab" data-bs-toggle="tab" href="#ps5" role="tab" aria-controls="ps5"
          aria-selected="false">PS5</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" id="xbox-tab" data-bs-toggle="tab" href="#xbox" role="tab" aria-controls="xbox"
          aria-selected="false">Xbox</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" id="xbox-tab" data-bs-toggle="tab" href="#nintendo" role="tab" aria-controls="xbox"
          aria-selected="false">Nintendo</a>
      </li>
    </ul>
  </div>

  <div class="tab-content">
    <div class="tab-pane fade show active" id="ps4" role="tabpanel" aria-labelledby="ps4-tab">
      <h3>Juegos PS4</h3>
      <div class="row g-4">
        {% for producto in productos %}
        {% if producto.categoria_id == 1 %}
        <div class="col-md-3">
          <div class="card h-100" style="width:200px">
            <img class="card-img-top" src="{{producto.imagen.url}}" alt="Card image">
            <div class="card-body">
              <h4 class="card-title">{{producto.nombre}}</h4>
              <p class="card-text">{{producto.precio}} €</p>
              <a href="#" class="btn btn-primary">See Profile</a>
            </div>
          </div>
        </div>
        {% endif %}
        {% endfor %}
      </div>
    </div>

    <div class="tab-pane fade" id="ps5" role="tabpanel" aria-labelledby="ps5-tab">
      <h3>Juegos PS5</h3>
      <!-- Contenido para juegos PS5 -->
      <div class="row g-4">
        {% for producto in productos %}
          {% if producto.categoria_id == 2 %}
            <div class="col-md-3">
              <div class="card h-100" style="width:200px">
                <img class="card-img-top" src="{{producto.imagen.url}}" alt="Card image">
                <div class="card-body">
                  <h4 class="card-title">{{producto.nombre}}</h4>
                  <p class="card-text">{{producto.precio}} €</p>
                  <a href="#" class="btn btn-primary">See Profile</a>
                </div>
              </div>
            </div>
          {% endif %}
        {% endfor %}
      </div>
    </div>
    <div class="tab-pane fade" id="xbox" role="tabpanel" aria-labelledby="xbox-tab">
      <h3>Juegos Xbox</h3>
      <!-- Contenido para juegos Xbox -->
      <div class="row g-4">
        {% for producto in productos %}
        {% if producto.categoria_id == 3 %}
        <div class="col-md-3">
          <div class="card h-100" style="width:200px">
            <img class="card-img-top" src="{{producto.imagen.url}}" alt="Card image">
            <div class="card-body">
              <h4 class="card-title">{{producto.nombre}}</h4>
              <p class="card-text">{{producto.precio}} €</p>
              <a href="#" class="btn btn-primary">See Profile</a>
            </div>
          </div>
        </div>
        {% endif %}
        {% endfor %}
      </div>
    </div>
    <div class="tab-pane fade" id="nintendo" role="tabpanel" aria-labelledby="xbox-tab">
      <h3>Juegos Nintendo</h3>
      <!-- Contenido para juegos Nintendo -->
      <div class="row g-4">
        {% for producto in productos %}
        {% if producto.categoria_id == 4 %}
        <div class="col-md-3">
          <div class="card h-100" style="width:200px">
            <img class="card-img-top" src="{{producto.imagen.url}}" alt="Card image">
            <div class="card-body">
              <h4 class="card-title">{{producto.nombre}}</h4>
              <p class="card-text">{{producto.precio}} €</p>
              <a href="#" class="btn btn-primary">See Profile</a>
            </div>
          </div>
        </div>
        {% endif %}
        {% endfor %}
      </div>
    </div>
  </div>
</div>
{% endblock %}

Esta plantilla de Django es utilizada para renderizar una página web que muestra diferentes juegos de consolas divididos en pestañas. A continuación, explicaré cada parte de la plantilla en detalle:

  1. Carga de la plantilla base:

/PracticaDjango/Tienda/templates/Tienda/tienda.html

{% extends "Proyecto_web_app/base.html" %}
Esta línea indica que esta plantilla hereda de otra plantilla base llamada "base.html". La plantilla base es utilizada para establecer la estructura común de todas las páginas en el proyecto.


2. Establecimiento del título de la página:

/PracticaDjango/Tienda/templates/Tienda/tienda.html

{% block title %}Tienda{% endblock %}
Aquí se define el título de la página, que se mostrará en la pestaña del navegador. En este caso, el título se establece como "Tienda".

3. Definición del contenido:

/PracticaDjango/Tienda/templates/Tienda/tienda.html

{% block content %}
...
{% endblock %}
Todo el contenido de la página se encuentra dentro de este bloque. Permite que la plantilla base reemplace este bloque con contenido específico de cada página.

4. Encabezado:

/PracticaDjango/Tienda/templates/Tienda/tienda.html

<h1 class="text-center">Elige tu Consola.</h1>
Este es un encabezado de nivel 1 que se muestra en la página. Muestra el texto "Elige tu Consola." y se alinea al centro.

5. División en pestañas:

/PracticaDjango/Tienda/templates/Tienda/tienda.html

<div class="container">
  <div class="bg-dark">
    <ul class="nav nav-tabs">
      ...
    </ul>
  </div>

En esta sección se crea un conjunto de pestañas utilizando el componente de navegación de Bootstrap. Cada pestaña representa una categoría de juegos de consolas.

6. Contenido de las pestañas:

/PracticaDjango/Tienda/templates/Tienda/tienda.html

<div class="tab-content">
  <div class="tab-pane fade show active" id="ps4" role="tabpanel" aria-labelledby="ps4-tab">
    ...
  </div>
  <div class="tab-pane fade" id="ps5" role="tabpanel" aria-labelledby="ps5-tab">
    ...
  </div>
  <div class="tab-pane fade" id="xbox" role="tabpanel" aria-labelledby="xbox-tab">
    ...
  </div>
  <div class="tab-pane fade" id="nintendo" role="tabpanel" aria-labelledby="xbox-tab">
    ...
  </div>
</div>
Aquí se define el contenido de cada pestaña. Cada bloque <div class="tab-pane fade"> representa el contenido de una pestaña específica. El atributo id identifica el contenido de cada pestaña, y el atributo role especifica el papel de la pestaña.

7. Bucle de juegos por categoría:

/PracticaDjango/Tienda/templates/Tienda/tienda.html

{% for producto in productos %}
  {% if producto.categoria_id == 1 %}
  ...
  {% endif %}
{% endfor %}
La variable "productos" se la hemos pasado a la plantilla a través de la vista y recoge todos los juegos que tenemos en la tienda. Este objeto tiene todos los juegos, independientemente de su categoría, es por ello por lo que tenemos que iterar sobre ellos y usar un condicional para que solo muestre en cada pestaña que hemos creado los juegos que pertenecen a la misma.

En otras palabras este es un bucle for de Django que itera sobre una lista de productos. Dentro del bucle, se comprueba si el producto pertenece a una categoría específica (identificada por el atributo categoria_id). En este ejemplo, se muestra el código 1 ya que corresponde a la categoria_id de PS4. La 2 es la de PS5, la 3 es XBOX y la 4 a Nintendo.

8. Tarjetas de juego.

Una vez que ya tenemos que juegos pertenecen a cada pestaña vamos a mostrar los mismos usando las cards de Bootstrap. Para que quede bien, vamos a poner cuatro cartas en cada fila.

/PracticaDjango/Tienda/templates/Tienda/tienda.html

<div class="col-md-3">
  <div class="card h-100" style="width:200px">
    <img class="card-img-top" src="{{producto.imagen.url}}" alt="Card image">
    <div class="card-body">
      <h4 class="card-title">{{producto.nombre}}</h4>
      <p class="card-text">{{producto.precio}} €</p>
      <a href="#" class="btn btn-primary">See Profile</a>
    </div>
  </div>
</div>
Este bloque representa una tarjeta de juego individual que se muestra en la página. Muestra la imagen del juego (producto.imagen.url), el nombre del juego (producto.nombre), el precio (producto.precio) y un botón de "See Profile". Se utiliza la sintaxis de plantillas de Django ({{ ... }}) para incrustar los valores de los atributos de los productos dentro de la plantilla.

Entremos un poco más en detalles.

Todo este código esta englobado en una fila, ya que hemos utilizado:

/PracticaDjango/Tienda/templates/Tienda/tienda.html

<div class="row g-4">
  ...
</div>

La línea <div class="row g-4"> es una clase de Bootstrap 5 que se utiliza para crear una fila (row) en un sistema de grillas (grid). A continuación se explica su significado:

  • <div>: Es un elemento HTML de división utilizado para agrupar contenido.

  • class="row": Es una clase de Bootstrap que define una fila en el sistema de grillas. Las filas son utilizadas para organizar el contenido en columnas dentro de un contenedor.

  • g-4: Es una clase de Bootstrap que agrega un espacio (g) entre las columnas dentro de la fila. El número 4 indica el tamaño del espacio en píxeles. En este caso, se establece un espacio de 4 píxeles entre las columnas.
Bien, ahora que tenemos una fila queremos que se distribuyan cuatro cartas por cada fila. ¿Y como conseguimos esto? Pues muy sencillo, como cada fila o "row" de bootstrap consta de 12 columnas  y queremos poner 4 juegos en cada fila, le corresponderían 3 columnas para cada juego. ( 4 juegos * 3 columnas = 12 columnas totales)

Lo reflejamos con el siguiente código:

/PracticaDjango/Tienda/templates/Tienda/tienda.html

<div class="col-md-3">
...
</div>
El resumen de todo lo anterior es que esta plantilla en particular renderiza una página que muestra juegos de diferentes consolas en pestañas separadas. Cada pestaña contiene tarjetas de juegos correspondientes a la categoría de consola respectiva. La plantilla hace uso de la herencia de plantillas, carga de contenido estático, bucles y condicionales para generar dinámicamente el contenido de la página.

Una vez realizado lo anterior se vería algo así como esto:

ejemplo de tienda web


Puedes encontrar el código de este capítulo en este enlace en github.

Anexo.

Creación de miniaturas de imagen usando easy-thumbnails

Estamos mostrando las imágenes originales en la página de la tienda, pero las dimensiones de diferentes imágenes pueden variar considerablemente. El tamaño de archivo de algunas imágenes puede ser muy grande y cargarlas podría llevar demasiado tiempo.

La mejor manera de mostrar imágenes optimizadas de manera uniforme es generar miniaturas. Una miniatura es una representación pequeña de una imagen más grande. Las miniaturas cargarán más rápido en el navegador y son una excelente manera de homogeneizar imágenes de tamaños muy diferentes. Utilizaremos una aplicación de Django llamada easy-thumbnails para generar miniaturas de las imágenes de los diferentes juegos de la tienda.

Abre la terminal e instala easy-thumbnails usando el siguiente comando:

pip install easy-thumbnails

Edita el archivo settings.py del proyecto y agrega easy_thumbnails al ajuste INSTALLED_APPS, de la siguiente manera:

PracticaDjango/PracticaDjango/settings.py

INSTALLED_APPS = [
    #...
    # Aplicaciones de terceros
    #...
    'easy_thumbnails',

Luego, ejecuta el siguiente comando para sincronizar la aplicación con tu base de datos:

python manage.py migrate

La aplicación easy-thumbnails te ofrece diferentes formas de definir miniaturas de imágenes. La aplicación proporciona una etiqueta de plantilla {% thumbnail %} para generar miniaturas en plantillas y un campo de imagen personalizado (ImageField) si deseas definir miniaturas en tus modelos. Vamos a utilizar el enfoque de la etiqueta de plantilla para las imagenes de las tarjetas de la tienda.
Edita la plantilla Tienda/tienda.html de la aplicación Tienda y modifícala con el código resaltado en azul:

PracticaDjango/Tienda/templates/Tienda/tienda.html

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

<!-- ... -->

<div class="tab-pane fade show active" id="ps4" role="tabpanel" aria-labelledby="ps4-tab">
      <h3>Juegos PS4</h3>
      <div class="row g-4">
        {% for producto in productos %}
        {% if producto.categoria_id == 1 %}
        <div class="col-md-3">
          <div class="card h-100" style="width:200px">
            <!-- <img class="card-img-top" src="{{producto.imagen.url}}" alt="Card image"> -->
            <img class="card-img-top" src="{% thumbnail producto.imagen 200x0 %}" alt="Card image">
            <div class="card-body">
              <h4 class="card-title">{{producto.nombre}}</h4>
              <p class="card-text">{{producto.precio}} €</p>
            </div>
            <div class="card-footer text-center">
              <a href="{% url 'carro:agregar' producto.id %}" class="btn btn-success">Agregar al Carro</a>
            </div>
          </div>
        </div>

Hemos definido una miniatura con un ancho fijo de 200 píxeles y una altura flexible para mantener la relación de aspecto utilizando el valor 0. La primera vez que un usuario carga esta página, se creará una imagen en miniatura. La miniatura se almacena en el mismo directorio que el archivo original. La ubicación está definida por el ajuste MEDIA_ROOT y el atributo upload_to del campo de imagen del modelo Producto. La miniatura generada luego será servida en las siguientes peticiones.
Ejecuta el servidor de desarrollo con el siguiente comando desde la terminal:

python manage.py runserver

Accede a la página de la tienda y compara la diferencia con la versión anterior.

pagina de tienda usando miniaturas


Si haces clic en una de las imágenes y la abres en una nueva pestaña


dirección url de la imagen


El nombre de archivo original va seguido de detalles adicionales de la configuración utilizada para crear la miniatura. Para una imagen PNG, verás un nombre de archivo como filename.png.200x0_q85.png, donde 200x0 son los parámetros de tamaño utilizados para generar la miniatura y 85 es el valor para la calidad predeterminada PNG utilizada por la biblioteca para generar la miniatura.

Puedes usar un valor de calidad diferente utilizando el parámetro quality. Para establecer la calidad PNG más alta, puedes usar el valor 100, así: {% thumbnail image.image 200x0 quality=100 %}. Una mayor calidad implicará un tamaño de archivo más grande.

La aplicación easy-thumbnails ofrece varias opciones para personalizar tus miniaturas, incluyendo algoritmos de recorte y diferentes efectos que se pueden aplicar. Si encuentras problemas al generar miniaturas, puedes agregar THUMBNAIL_DEBUG = True al archivo settings.py para obtener información de depuración.

Puedes leer la documentación completa de easy-thumbnails en https://easy-thumbnails.readthedocs.io/.




No hay comentarios:

Publicar un comentario