Finish Form Rewrite
This commit is contained in:
@@ -1,11 +0,0 @@
|
|||||||
from jinja2 import Environment
|
|
||||||
from django.urls import reverse
|
|
||||||
from django.templatetags.static import static
|
|
||||||
|
|
||||||
def environment(**options):
|
|
||||||
env = Environment(**options)
|
|
||||||
env.globals.update({
|
|
||||||
'static': static,
|
|
||||||
'url': reverse,
|
|
||||||
})
|
|
||||||
return env
|
|
||||||
+10
-9
@@ -14,6 +14,7 @@ import logging
|
|||||||
import os, sys
|
import os, sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
DEV_ENV = (sys.argv[1] == 'runserver')
|
||||||
|
|
||||||
RUNNING_TESTS = any(arg in {'test', 'pytest'} for arg in sys.argv) or 'PYTEST_CURRENT_TEST' in os.environ
|
RUNNING_TESTS = any(arg in {'test', 'pytest'} for arg in sys.argv) or 'PYTEST_CURRENT_TEST' in os.environ
|
||||||
|
|
||||||
@@ -101,6 +102,7 @@ INSTALLED_APPS = [
|
|||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
|
'django.forms',
|
||||||
'compressor',
|
'compressor',
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -136,14 +138,6 @@ TEMPLATES = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
'BACKEND': 'django.template.backends.jinja2.Jinja2',
|
|
||||||
'DIRS': [BASE_DIR / 'templates/jinja2'],
|
|
||||||
'APP_DIRS': True,
|
|
||||||
'OPTIONS': {
|
|
||||||
'environment': 'proyecto.jinja2.environment',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
|
||||||
WSGI_APPLICATION = 'proyecto.wsgi.application'
|
WSGI_APPLICATION = 'proyecto.wsgi.application'
|
||||||
@@ -429,4 +423,11 @@ CELERY_RESULT_SERIALIZER = 'json'
|
|||||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||||
|
|
||||||
USE_X_FORWARDED_HOST = True
|
USE_X_FORWARDED_HOST = True
|
||||||
SECURE_REFERER_POLICY = "strict-origin-when-cross-origin"
|
SECURE_REFERER_POLICY = "strict-origin-when-cross-origin"
|
||||||
|
|
||||||
|
from django.forms.renderers import TemplatesSetting
|
||||||
|
|
||||||
|
class CustomFormRenderer(TemplatesSetting):
|
||||||
|
form_template_name = "tienda/form_snippet.html"
|
||||||
|
|
||||||
|
FORM_RENDERER = "proyecto.settings.CustomFormRenderer"
|
||||||
+27
-22
@@ -1,46 +1,51 @@
|
|||||||
amqp==5.3.1
|
amqp==5.3.1
|
||||||
asgiref==3.11.0
|
asgiref==3.11.1
|
||||||
billiard==4.2.4
|
billiard==4.2.4
|
||||||
celery==5.6.2
|
boto3==1.43.5
|
||||||
certifi==2026.1.4
|
botocore==1.43.5
|
||||||
|
celery==5.6.3
|
||||||
|
certifi==2026.4.22
|
||||||
cffi==2.0.0
|
cffi==2.0.0
|
||||||
charset-normalizer==3.4.4
|
charset-normalizer==3.4.7
|
||||||
click==8.3.1
|
click==8.3.3
|
||||||
click-didyoumean==0.3.1
|
click-didyoumean==0.3.1
|
||||||
click-plugins==1.1.1.2
|
click-plugins==1.1.1.2
|
||||||
click-repl==0.3.0
|
click-repl==0.3.0
|
||||||
cryptography==46.0.7
|
cryptography==48.0.0
|
||||||
Django==6.0.4
|
defusedxml==0.7.1
|
||||||
|
Django==6.0.5
|
||||||
django-appconf==1.2.0
|
django-appconf==1.2.0
|
||||||
django-redis==5.4.0
|
django-redis==6.0.0
|
||||||
|
django-storages==1.14.6
|
||||||
django_compressor==4.6.0
|
django_compressor==4.6.0
|
||||||
django-storages[boto3]==1.14.6
|
fonttools==4.62.1
|
||||||
gunicorn==25.1.0
|
fpdf2==2.8.7
|
||||||
idna==3.11
|
gunicorn==26.0.0
|
||||||
Jinja2==3.1.6
|
idna==3.13
|
||||||
|
|
||||||
|
jmespath==1.1.0
|
||||||
kombu==5.6.2
|
kombu==5.6.2
|
||||||
MarkupSafe==3.0.3
|
MarkupSafe==3.0.3
|
||||||
packaging==26.0
|
packaging==26.2
|
||||||
paypalrestsdk==1.13.3
|
paypalrestsdk==1.13.3
|
||||||
pillow==12.2.0
|
pillow==12.2.0
|
||||||
boto3==1.42.97
|
|
||||||
prompt_toolkit==3.0.52
|
prompt_toolkit==3.0.52
|
||||||
|
psycopg2-binary==2.9.12
|
||||||
pycparser==3.0
|
pycparser==3.0
|
||||||
pyOpenSSL==26.0.0
|
pyOpenSSL==26.2.0
|
||||||
python-dateutil==2.9.0.post0
|
python-dateutil==2.9.0.post0
|
||||||
rcssmin==1.2.2
|
rcssmin==1.2.2
|
||||||
redis==5.2.1
|
redis==7.4.0
|
||||||
requests==2.33.0
|
requests==2.33.1
|
||||||
rjsmin==1.2.5
|
rjsmin==1.2.5
|
||||||
|
s3transfer==0.17.0
|
||||||
six==1.17.0
|
six==1.17.0
|
||||||
sqlparse==0.5.5
|
sqlparse==0.5.5
|
||||||
stripe==14.3.0
|
stripe==15.1.0
|
||||||
typing_extensions==4.15.0
|
typing_extensions==4.15.0
|
||||||
tzdata==2025.3
|
tzdata==2026.2
|
||||||
tzlocal==5.3.1
|
tzlocal==5.3.1
|
||||||
urllib3==2.6.3
|
urllib3==2.6.3
|
||||||
vine==5.1.0
|
vine==5.1.0
|
||||||
wcwidth==0.6.0
|
wcwidth==0.7.0
|
||||||
whitenoise==6.12.0
|
whitenoise==6.12.0
|
||||||
fpdf2==2.8.7
|
|
||||||
psycopg2-binary==2.9.11
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 6.0.4 on 2026-05-07 08:14
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('tienda', '0007_add_product_sku'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='product',
|
||||||
|
name='briefdesc',
|
||||||
|
field=models.TextField(default='', max_length=250),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='product',
|
||||||
|
name='description',
|
||||||
|
field=models.TextField(default='', max_length=5000),
|
||||||
|
),
|
||||||
|
]
|
||||||
+1
-1
@@ -86,7 +86,7 @@ class Product(models.Model):
|
|||||||
name = models.CharField(max_length=200, default="")
|
name = models.CharField(max_length=200, default="")
|
||||||
sku = models.CharField(max_length=50, unique=True, blank=True, null=True)
|
sku = models.CharField(max_length=50, unique=True, blank=True, null=True)
|
||||||
description = models.TextField(default = "", max_length=5000)
|
description = models.TextField(default = "", max_length=5000)
|
||||||
briefdesc = models.TextField(default = "", max_length=1000)
|
briefdesc = models.TextField(default = "", max_length=250)
|
||||||
price = models.FloatField(default = 0)
|
price = models.FloatField(default = 0)
|
||||||
stock = models.PositiveIntegerField(default=0)
|
stock = models.PositiveIntegerField(default=0)
|
||||||
category = models.ForeignKey(Category, on_delete=models.CASCADE)
|
category = models.ForeignKey(Category, on_delete=models.CASCADE)
|
||||||
|
|||||||
+4
-8
@@ -11,21 +11,19 @@ from .models import User, VerificationCode
|
|||||||
@shared_task
|
@shared_task
|
||||||
def enviar_correo_bienvenida(email_usuario: str, nombre_usuario: str):
|
def enviar_correo_bienvenida(email_usuario: str, nombre_usuario: str):
|
||||||
html_content = render_to_string(
|
html_content = render_to_string(
|
||||||
'emails/welcome.html',
|
'tienda/emails/welcome.html',
|
||||||
{
|
{
|
||||||
"name": nombre_usuario
|
"name": nombre_usuario
|
||||||
},
|
},
|
||||||
using='jinja2'
|
|
||||||
)
|
)
|
||||||
send_hemail(email_usuario, "Inicio de Sesión correcto", html_content, "Has iniciado sesión...")
|
send_hemail(email_usuario, "Inicio de Sesión correcto", html_content, "Has iniciado sesión...")
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def banear_usuario(email_usuario: str):
|
def banear_usuario(email_usuario: str):
|
||||||
html_content = render_to_string(
|
html_content = render_to_string(
|
||||||
'emails/ban.html',
|
'tienda/emails/ban.html',
|
||||||
{
|
{
|
||||||
},
|
},
|
||||||
using='jinja2'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
send_hemail(email_usuario, "Cuenta Bloqueada", html_content, "Tu cuenta ha sido bloqueada...")
|
send_hemail(email_usuario, "Cuenta Bloqueada", html_content, "Tu cuenta ha sido bloqueada...")
|
||||||
@@ -33,9 +31,8 @@ def banear_usuario(email_usuario: str):
|
|||||||
@shared_task
|
@shared_task
|
||||||
def desbanear_usuario(email_usuario: str):
|
def desbanear_usuario(email_usuario: str):
|
||||||
html_content = render_to_string(
|
html_content = render_to_string(
|
||||||
'emails/unban.html',
|
'tienda/emails/unban.html',
|
||||||
{},
|
{},
|
||||||
using='jinja2'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
send_hemail(email_usuario, "Cuenta Desbloqueada", html_content, "Tu cuenta ha sido desbloqueada...")
|
send_hemail(email_usuario, "Cuenta Desbloqueada", html_content, "Tu cuenta ha sido desbloqueada...")
|
||||||
@@ -67,14 +64,13 @@ def enviar_correo_recuperacion(email: str):
|
|||||||
)
|
)
|
||||||
ver_code.save()
|
ver_code.save()
|
||||||
html_content = render_to_string(
|
html_content = render_to_string(
|
||||||
'emails/reset_pass.html',
|
'tienda/emails/reset_pass.html',
|
||||||
{
|
{
|
||||||
"name": usuario.get_full_name(),
|
"name": usuario.get_full_name(),
|
||||||
"domain": settings.DOMAIN,
|
"domain": settings.DOMAIN,
|
||||||
"protocol": settings.PROTOCOL,
|
"protocol": settings.PROTOCOL,
|
||||||
"code": ver_code.code
|
"code": ver_code.code
|
||||||
},
|
},
|
||||||
using='jinja2'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
send_hemail(email, "Reset de Contraseña", html_content, "Estas reseteando la contraseña...")
|
send_hemail(email, "Reset de Contraseña", html_content, "Estas reseteando la contraseña...")
|
||||||
|
|||||||
@@ -13,74 +13,7 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form method="POST" enctype="multipart/form-data">
|
<form method="POST" enctype="multipart/form-data">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
<!-- Nombre del producto -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="name" class="form-label">Nombre del Producto <span class="text-danger">*</span></label>
|
|
||||||
<input type="text" class="form-control" id="name" name="name" required maxlength="200"
|
|
||||||
placeholder="Ej: iPhone 15 Pro Max">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Descripción breve -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="briefdesc" class="form-label">Descripción Breve</label>
|
|
||||||
<input type="text" class="form-control" id="briefdesc" name="briefdesc" maxlength="250"
|
|
||||||
placeholder="Una descripción corta para mostrar en las tarjetas de producto">
|
|
||||||
<div class="form-text">Opcional. Se mostrará en las vistas de listado de productos.</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Descripción completa -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="description" class="form-label">Descripción Completa <span class="text-danger">*</span></label>
|
|
||||||
<textarea class="form-control" id="description" name="description" rows="5" required
|
|
||||||
placeholder="Describe tu producto en detalle..."></textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Precio -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="price" class="form-label">Precio <span class="text-danger">*</span></label>
|
|
||||||
<div class="input-group">
|
|
||||||
<span class="input-group-text">€</span>
|
|
||||||
<input type="number" class="form-control" id="price" name="price" required
|
|
||||||
min="0" step="0.01" placeholder="0.00">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Stock -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="stock" class="form-label">Stock disponible <span class="text-danger">*</span></label>
|
|
||||||
<input type="number" class="form-control" id="stock" name="stock" required
|
|
||||||
min="0" step="1" placeholder="0">
|
|
||||||
<div class="form-text">Cantidad máxima que podrán comprar los clientes.</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Categoría -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="category" class="form-label">Categoría <span class="text-danger">*</span></label>
|
|
||||||
<select class="form-select" id="category" name="category" required>
|
|
||||||
<option value="" selected disabled>Selecciona una categoría</option>
|
|
||||||
{% for category in categories %}
|
|
||||||
<option value="{{ category.id }}">{{ category.name }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Imagen principal -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="primary_image" class="form-label">Imagen Principal</label>
|
|
||||||
<input type="file" class="form-control" id="primary_image" name="primary_image"
|
|
||||||
accept="image/*">
|
|
||||||
<div class="form-text">Opcional. Esta será la imagen destacada del producto.</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Imágenes secundarias -->
|
|
||||||
<div class="mb-4">
|
|
||||||
<label for="secondary_images" class="form-label">Imágenes Secundarias</label>
|
|
||||||
<input type="file" class="form-control" id="secondary_images" name="secondary_images"
|
|
||||||
accept="image/*" multiple>
|
|
||||||
<div class="form-text">Opcional. Puedes seleccionar múltiples imágenes adicionales.</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Botones -->
|
<!-- Botones -->
|
||||||
<div class="d-flex justify-content-end gap-2">
|
<div class="d-flex justify-content-end gap-2">
|
||||||
<a href="{% url 'mis_productos' %}" class="btn btn-secondary">Cancelar</a>
|
<a href="{% url 'mis_productos' %}" class="btn btn-secondary">Cancelar</a>
|
||||||
|
|||||||
@@ -24,4 +24,4 @@
|
|||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
+1
-1
@@ -18,4 +18,4 @@
|
|||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
+1
-1
@@ -24,4 +24,4 @@
|
|||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -24,4 +24,4 @@
|
|||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -23,4 +23,4 @@
|
|||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{% for field in form %}
|
||||||
|
<div class="mb-3">
|
||||||
|
{{ field.errors }}
|
||||||
|
{{ field.label_tag }} {{ field }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
{% extends "tienda/base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row mt-4 mb-5">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<div>
|
||||||
|
<h2>Gestionar Imágenes</h2>
|
||||||
|
<p class="text-muted mb-0">Producto: <strong>{{ producto.name }}</strong></p>
|
||||||
|
</div>
|
||||||
|
<a href="{% url 'mis_productos' %}" class="btn btn-outline-secondary">← Volver a Mis Productos</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header">
|
||||||
|
<h5 class="mb-0">Imagen Principal</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
{% if producto.primary_image %}
|
||||||
|
<img src="{{ producto.primary_image.image.url }}" alt="{{ producto.primary_image.alt|default:producto.name }}" class="rounded" style="width: 200px; height: 200px; object-fit: cover;">
|
||||||
|
<p class="mt-2 text-muted mb-0">Esta imagen no se puede cambiar desde aquí.</p>
|
||||||
|
{% else %}
|
||||||
|
<p class="text-muted">No hay imagen principal asignada.</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<h5 class="mb-0">Imágenes Secundarias</h5>
|
||||||
|
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#agregarImagenModal">
|
||||||
|
➕ Agregar Imagen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
{% if secondary_images %}
|
||||||
|
<div class="row">
|
||||||
|
{% for img in secondary_images %}
|
||||||
|
<div class="col-md-3 col-sm-4 col-6 mb-3">
|
||||||
|
<div class="card">
|
||||||
|
<img src="{{ img.image.url }}" alt="{{ img.alt|default:producto.name }}" class="card-img-top" style="height: 180px; object-fit: cover;">
|
||||||
|
<div class="card-body p-2">
|
||||||
|
<form method="POST" action="{% url 'eliminar_imagen_secundaria' producto.id img.id %}" onsubmit="return confirm('¿Seguro que quieres eliminar esta imagen?');">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button type="submit" class="btn btn-outline-danger btn-sm w-100">🗑 Eliminar</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p class="text-muted text-center py-4">No hay imágenes secundarias. ¡Agrega una!</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="agregarImagenModal" tabindex="-1" aria-labelledby="agregarImagenModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="agregarImagenModalLabel">Agregar Imagen Secundaria</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<form method="POST" enctype="multipart/form-data">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="modal-body">
|
||||||
|
{{ form }}
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
|
||||||
|
<button type="submit" class="btn btn-primary">Subir Imagen</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -12,22 +12,7 @@
|
|||||||
<form method="post" action="{% url 'login' %}">
|
<form method="post" action="{% url 'login' %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
<div class="mb-3">
|
{{ form }}
|
||||||
<label for="loginEmail" class="form-label">Correo Electrónico</label>
|
|
||||||
<input type="email" class="form-control" id="loginEmail" name="email" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="loginPassword" class="form-label">Contraseña</label>
|
|
||||||
<input type="password" class="form-control" id="loginPassword" name="password" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3 form-check">
|
|
||||||
<input type="checkbox" class="form-check-input" id="rememberMe" name="remember">
|
|
||||||
<label class="form-check-label" for="rememberMe">
|
|
||||||
Recordarme
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-grid gap-2">
|
<div class="d-grid gap-2">
|
||||||
<button type="submit" class="btn btn-primary">Iniciar Sesión</button>
|
<button type="submit" class="btn btn-primary">Iniciar Sesión</button>
|
||||||
|
|||||||
@@ -57,6 +57,7 @@
|
|||||||
<td class="text-end">{{ producto.stock }}</td>
|
<td class="text-end">{{ producto.stock }}</td>
|
||||||
<td class="text-end">
|
<td class="text-end">
|
||||||
<div class="d-flex justify-content-end gap-2">
|
<div class="d-flex justify-content-end gap-2">
|
||||||
|
<a href="{% url 'gestionar_imagenes' producto.id %}" class="btn btn-outline-secondary btn-sm">Gestionar Imágenes</a>
|
||||||
<a href="{% url 'editar_producto' producto.id %}" class="btn btn-outline-primary btn-sm">Editar</a>
|
<a href="{% url 'editar_producto' producto.id %}" class="btn btn-outline-primary btn-sm">Editar</a>
|
||||||
<form method="POST" action="{% url 'borrar_producto' producto.id %}" onsubmit="return confirm('¿Seguro que quieres borrar este producto?');">
|
<form method="POST" action="{% url 'borrar_producto' producto.id %}" onsubmit="return confirm('¿Seguro que quieres borrar este producto?');">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|||||||
@@ -12,33 +12,7 @@
|
|||||||
<form method="post" action="{% url 'register' %}">
|
<form method="post" action="{% url 'register' %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
<div class="mb-3">
|
{{ form }}
|
||||||
<label for="registerName" class="form-label">Nombre Completo</label>
|
|
||||||
<input type="text" class="form-control" id="registerName" name="name" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="registerEmail" class="form-label">Correo Electrónico</label>
|
|
||||||
<input type="email" class="form-control" id="registerEmail" name="email" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="registerPassword" class="form-label">Contraseña</label>
|
|
||||||
<input type="password" class="form-control" id="registerPassword" name="password" required>
|
|
||||||
<div class="form-text">La contraseña debe tener al menos 8 caracteres.</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="registerPasswordConfirm" class="form-label">Confirmar Contraseña</label>
|
|
||||||
<input type="password" class="form-control" id="registerPasswordConfirm" name="password_confirm" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3 form-check">
|
|
||||||
<input type="checkbox" class="form-check-input" id="acceptTerms" name="terms" required>
|
|
||||||
<label class="form-check-label" for="acceptTerms">
|
|
||||||
Acepto los <a href="{% url 'terminos' %}" target="_blank">términos y condiciones</a>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-grid gap-2">
|
<div class="d-grid gap-2">
|
||||||
<button type="submit" class="btn btn-primary">Crear Cuenta</button>
|
<button type="submit" class="btn btn-primary">Crear Cuenta</button>
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ urlpatterns = [
|
|||||||
path("venta/crear-producto/", views.crear_producto, name="crear_producto"),
|
path("venta/crear-producto/", views.crear_producto, name="crear_producto"),
|
||||||
path("venta/editar-producto/<int:id>/", views.editar_producto, name="editar_producto"),
|
path("venta/editar-producto/<int:id>/", views.editar_producto, name="editar_producto"),
|
||||||
path("venta/borrar-producto/<int:id>/", views.borrar_producto, name="borrar_producto"),
|
path("venta/borrar-producto/<int:id>/", views.borrar_producto, name="borrar_producto"),
|
||||||
|
path("venta/gestionar-imagenes/<int:id>/", views.gestionar_imagenes, name="gestionar_imagenes"),
|
||||||
|
path("venta/gestionar-imagenes/<int:product_id>/eliminar/<int:image_id>/", views.eliminar_imagen_secundaria, name="eliminar_imagen_secundaria"),
|
||||||
# Carrito
|
# Carrito
|
||||||
path("cart/", views.view_cart, name="view_cart"),
|
path("cart/", views.view_cart, name="view_cart"),
|
||||||
path("cart/add/<int:product_id>/", views.add_to_cart, name="add_to_cart"),
|
path("cart/add/<int:product_id>/", views.add_to_cart, name="add_to_cart"),
|
||||||
|
|||||||
Reference in New Issue
Block a user