Implementación de Registro con Subida de Avatar Usando AJAX y Formularios en Django

Conversión entre Objetos jQuery y DOM Nativo

Para acceder al elemento DOM real desde un objeto jQuery, se utiliza la notación de índice [0]. Para envolver un eelmento DOM nativo con jQuery, se emplea la función $().

// jQuery a DOM nativo
var elementoDOM = $(selector)[0];

// DOM nativo a jQuery
var $elementojQuery = $(elementoDOM);

Actualizar Código de Verificación Dinámicamente

Para implementar un captcha que se renueve al hacer clic, se modifica el atributo src de la imagen añadiendo un parámetro aleatorio:


<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Formulario de Acceso</title>
    <link rel="stylesheet" href="/static/css/bootstrap.min.css">
    <style>
        .contenedor-formulario { margin-top: 80px; }
        .mensaje-error { color: #dc3545; font-size: 0.9em; }
    </style>
</head>
<body>
<div class="container">
    <div class="row justify-content-center contenedor-formulario">
        <div class="col-md-5">
            <form id="formulario-acceso">
                {% csrf_token %}
                <div class="mb-3">
                    <label for="campo-usuario" class="form-label">Usuario</label>
                    <input type="text" id="campo-usuario" name="nombre_usuario" class="form-control">
                </div>
                <div class="mb-3">
                    <label for="campo-clave" class="form-label">Contraseña</label>
                    <input type="password" id="campo-clave" name="clave" class="form-control">
                </div>
                <div class="mb-3">
                    <label for="campo-verificacion" class="form-label">Código de verificación</label>
                    <div class="row align-items-center">
                        <div class="col-6">
                            <input type="text" class="form-control" id="campo-verificacion">
                        </div>
                        <div class="col-6">
                            <img src="/generar-captcha/" width="140" height="45" id="imagen-captcha" alt="captcha">
                        </div>
                    </div>
                </div>
                <button type="button" id="boton-enviar" class="btn btn-primary w-100">Iniciar Sesión</button>
                <p class="mensaje-error mt-2" id="texto-error"></p>
            </form>
        </div>
    </div>
</div>

<script src="/static/js/jquery.min.js"></script>
<script>
    $('#boton-enviar').on('click', function() {
        var usuario = $('#campo-usuario').val();
        var contrasena = $('#campo-clave').val();
        var codigo = $('#campo-verificacion').val();

        $.ajax({
            url: '/autenticar/',
            method: 'POST',
            data: {
                nombre_usuario: usuario,
                clave: contrasena,
                codigo_verificacion: codigo
            },
            success: function(respuesta) {
                if (respuesta.exito) {
                    window.location.href = '/panel/';
                } else {
                    $('#texto-error').text(respuesta.mensaje);
                }
            }
        });
    });

    $('#imagen-captcha').on('click', function() {
        var elemento = this;
        elemento.src = elemento.src.split('?')[0] + '?' + Date.now();
    });
</script>
</body>
</html>

Métodos para Subir Archivos

Envío Mediante Formulario Tradicional

Configuración de rutas y vista en Django:

# urls.py
from django.urls import path
from aplicacion import vistas

urlpatterns = [
    path('registro/', vistas.registrar_usuario),
]

# vistas.py
from django.shortcuts import render, HttpResponse

def registrar_usuario(request):
    if request.method == 'POST':
        nombre = request.POST.get('nombre_usuario')
        archivo = request.FILES.get('documento')
        
        if archivo:
            ruta_destino = archivo.name
            with open(ruta_destino, 'wb') as destino:
                for fragmento in archivo.chunks():
                    destino.write(fragmento)
        
        return HttpResponse('Archivo almacenado correctamente')
    
    return render(request, 'registro.html')

Plantilla HTML con formulario estándar:


<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Registro de Usuario</title>
</head>
<body>
    <form action="/registro/" method="post" enctype="multipart/form-data">
        {% csrf_token %}
        <div>
            <label>Nombre de usuario:</label>
            <input type="text" name="nombre_usuario">
        </div>
        <div>
            <label>Seleccionar archivo:</label>
            <input type="file" name="documento">
        </div>
        <button type="submit">Enviar</button>
    </form>
</body>
</html>

Envío Mediante AJAX con FormData

# urls.py (mismo esquema anterior)
# vistas.py
from django.shortcuts import render, HttpResponse

def registrar_usuario(request):
    if request.method == 'POST':
        nombre = request.POST.get('nombre_usuario')
        archivo_subido = request.FILES.get('archivo_adjunto')
        
        if archivo_subido:
            with open(archivo_subido.name, 'wb') as destino:
                for porcion in archivo_subido:
                    destino.write(porcion)
        
        return HttpResponse('Procesado exitosamente')
    
    return render(request, 'registro.html')


<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Registro AJAX</title>
</head>
<body>
    <div>
        <label>Usuario:</label>
        <input type="text" id="input-nombre">
    </div>
    <div>
        <label>Archivo:</label>
        <input type="file" id="input-archivo">
    </div>
    <button id="btn-registrar">Registrar</button>

    <script src="/static/js/jquery.min.js"></script>
    <script>
        $('#btn-registrar').on('click', function() {
            var datosFormulario = new FormData();
            datosFormulario.append('nombre_usuario', $('#input-nombre').val());
            
            var archivoSeleccionado = $('#input-archivo')[0].files[0];
            datosFormulario.append('archivo_adjunto', archivoSeleccionado);

            $.ajax({
                url: '/registro/',
                type: 'POST',
                data: datosFormulario,
                contentType: false,
                processData: false,
                success: function(resultado) {
                    console.log('Respuesta:', resultado);
                }
            });
        });
    &;/script>
</body>
</html>

Formularios de Django con Campos Personalizados

Uso del sistema de formularios de Django para generar los controles del formulario:

# vistas.py
from django.shortcuts import render, HttpResponse
from django import forms
from django.forms import widgets

class FormularioRegistro(forms.Form):
    nombre_usuario = forms.CharField(
        max_length=50,
        label='Nombre de usuario',
        widget=widgets.TextInput(attrs={'class': 'form-control'})
    )
    clave_acceso = forms.CharField(
        max_length=50,
        label='Contraseña',
        widget=widgets.PasswordInput(attrs={'class': 'form-control'})
    )
    confirmar_clave = forms.CharField(
        max_length=50,
        label='Confirmar contraseña',
        widget=widgets.PasswordInput(attrs={'class': 'form-control'})
    )
    correo_electronico = forms.EmailField(
        label='Email',
        widget=widgets.EmailInput(attrs={'class': 'form-control'})
    )

def registrar_usuario(request):
    formulario = FormularioRegistro()
    
    if request.method == 'POST':
        formulario = FormularioRegistro(request.POST)
        
        if formulario.is_valid():
            nombre = formulario.cleaned_data['nombre_usuario']
            clave = formulario.cleaned_data['clave_acceso']
            archivo_avatar = request.FILES.get('imagen_perfil')
            
            if archivo_avatar:
                with open(archivo_avatar.name, 'wb') as f:
                    for chunk in archivo_avatar:
                        f.write(chunk)
            
            return HttpResponse('Registro completado')
    
    return render(request, 'registro.html', {'formulario': formulario})

Plantilla con selector de avatar oculto que se activa al hacer clic en la imagen:


<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Formulario de Registro</title>
    <style>
        .panel-formulario { margin-top: 60px; }
        #selector-avatar { display: none; }
        .miniatura-avatar { width: 60px; height: 60px; border-radius: 50%; cursor: pointer; }
    </style>
</head>
<body>
<div class="container">
    <div class="row justify-content-center panel-formulario">
        <div class="col-md-6">
            <form action="" method="post" enctype="multipart/form-data">
                {% csrf_token %}
                
                <div class="mb-3">
                    <label for="{{ formulario.nombre_usuario.id_for_label }}">{{ formulario.nombre_usuario.label }}</label>
                    {{ formulario.nombre_usuario }}
                </div>
                
                <div class="mb-3">
                    <label for="{{ formulario.clave_acceso.id_for_label }}">{{ formulario.clave_acceso.label }}</label>
                    {{ formulario.clave_acceso }}
                </div>
                
                <div class="mb-3">
                    <label for="{{ formulario.confirmar_clave.id_for_label }}">{{ formulario.confirmar_clave.label }}</label>
                    {{ formulario.confirmar_clave }}
                </div>
                
                <div class="mb-3">
                    <label>Foto de perfil</label><br>
                    <label for="selector-avatar">
                        <img src="/static/img/avatar-predeterminado.png" class="miniatura-avatar" id="vista-previa">
                    </label>
                    <input type="file" id="selector-avatar" name="imagen_perfil">
                </div>
                
                <button type="submit" class="btn btn-success">Crear cuenta</button>
            </form>
        </div>
    </div>
</div>

<script src="/static/js/jquery.min.js"></script>
<script>
    $('#selector-avatar').on('change', function() {
        var archivo = this.files[0];
        
        if (archivo) {
            var lector = new FileReader();
            
            lector.onload = function(evento) {
                $('#vista-previa').attr('src', evento.target.result);
            };
            
            lector.readAsDataURL(archivo);
        }
    });
</script>
</body>
</html>

Configuración de Rutas para Archivos Multimedia

Para almacenar los archivos subidos por los usuarios en el servidor, se configura la ruta de medios en Django:

# settings.py
import os

MEDIA_URL = '/archivos/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'aplicacion', 'media')

Se agrega una ruta para servir los archivos estáticos durante el desarrollo:

# urls.py
from django.urls import re_path
from django.views.static import serve
from django.conf import settings

urlpatterns = [
    # ... otras rutas ...
    re_path(r'^archivos/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
]

De esta forma, los archivos subidos se organizan dentro de la carpeta media del proyecto, permitiendo una gestión ordenada de los recursos de los usuarios.

Etiquetas: Django jQuery AJAX Formularios subida-archivos

Publicado el 7-23 17:14