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:
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 = [
...
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.
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
Registrando los modelos en el panel de administración.
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)
Construyendo las vistas.
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)
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:
Carga de la plantilla base:
/PracticaDjango/Tienda/templates/Tienda/tienda.html
{% extends "Proyecto_web_app/base.html" %}
/PracticaDjango/Tienda/templates/Tienda/tienda.html
{% block title %}Tienda{% endblock %}
/PracticaDjango/Tienda/templates/Tienda/tienda.html
{% block content %}
...
{% endblock %}
/PracticaDjango/Tienda/templates/Tienda/tienda.html
<h1 class="text-center">Elige tu Consola.</h1>
/PracticaDjango/Tienda/templates/Tienda/tienda.html
<div class="container">
<div class="bg-dark">
<ul class="nav nav-tabs">
...
</ul>
</div>
/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>
<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./PracticaDjango/Tienda/templates/Tienda/tienda.html
{% for producto in productos %}
{% if producto.categoria_id == 1 %}
...
{% endif %}
{% endfor %}
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./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>
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./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úmero4
indica el tamaño del espacio en píxeles. En este caso, se establece un espacio de 4 píxeles entre las columnas.
/PracticaDjango/Tienda/templates/Tienda/tienda.html
<div class="col-md-3">
...
</div>
Creación de miniaturas de imagen usando easy-thumbnails
PracticaDjango/PracticaDjango/settings.py
INSTALLED_APPS = [ #... # Aplicaciones de terceros #... 'easy_thumbnails',
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>
No hay comentarios:
Publicar un comentario