Configuración del frontend con AdminLTE y Bootstrap 3
Para este ejemplo, se utiliza AdminLTE como plantilla de frontend, basado en Bootstrap 3. Se implementa un sistema de selección en cascada donde la elección de una provincia actualiza dinámicamente las opciones de ciudad.
1. Estructura HTML
El HTML incluye dos menús desplegables para provincia y ciudad, con valores predeterminados proporcionados por el backend. Además, se agrega un botón para enviar los datos actualizados.
<div class="content">
<div class="box box-success">
<div class="box-header with-border">
<h3 class="box-title">Ejemplo de selección cascada</h3>
</div>
<div class="box-body">
<div class="row">
<div class="form-group col-xs-3">
<label>Seleccionar provincia</label>
<select class="form-control select2" id="provinceSelect">
<option selected="selected">{{ vehicle_data.province }}</option>
</select>
</div>
<div class="form-group col-xs-3">
<label>Seleccionar ciudad</label>
<select class="form-control select2" id="citySelect">
<option selected="selected">{{ vehicle_data.city }}</option>
</select>
</div>
</div>
</div>
</div>
</div>
<div class="footer">
<button type="button" class="btn btn-block btn-info btn-lg" style="width: 10%; height: 5%"
onclick="sendUpdatedData()">Guardar cambios</button>
</div>
Las variables de plantilla {{ vehicle_data.province }} y {{ vehicle_data.city }} representan los valores previamente guardados, establecidos como predeterminados en los menús desplegables.
2. Lógica JavaScript para el enlace cascada
Se define un objeto con la estructura de datos que mapea provincias a ciudades. Al cargar la página, las provincias se agregan al primer menú desplegable. Cuando el usuario selecciona una provincia, se actualizan dinámicamente las opciones del segundo menú.
// Elementos del DOM para los menús desplegables
const provinceDropdown = document.getElementById('provinceSelect');
const cityDropdown = document.getElementById('citySelect');
// Estructura de datos: provincias y sus ciudades correspondientes
const regionData = {
"Pekín": ['Dongcheng', 'Xicheng', 'Chongwen', 'Xuanwu', 'Chaoyang', 'Fengtai', 'Shijingshan', 'Haidian', 'Mentougou', 'Fangshan', 'Tongzhou', 'Shunyi', 'Changping', 'Daxing', 'Huairou', 'Pinggu', 'Miyun', 'Yanqing'],
"Shanghái": ['Huangpu', 'Luwan', 'Xuhui', 'Changning', 'Jing\'an', 'Putuo', 'Zhabei', 'Hongkou', 'Yangpu', 'Minhang', 'Baoshan', 'Jiading', 'Pudong', 'Jinshan', 'Songjiang', 'Qingpu', 'Nanhui', 'Fengxian', 'Chongming'],
"Chongqing": ['Wanzhou', 'Fuling', 'Yuzhong', 'Dadukou', 'Jiangbei', 'Shapingba', 'Jiulongpo', 'Nan\'an', 'Beibei', 'Wansheng', 'Shuangqiao', 'Yubei', 'Ban\'an', 'Qianjiang', 'Changshou', 'Jiangjin', 'Hechuan', 'Yongchuan', 'Nanchuan', 'Qijiang', 'Tongnan', 'Tongliang', 'Dazu', 'Rongchang', 'Bishan', 'Liangping', 'Chengkou', 'Fengdu', 'Dianjiang', 'Wulong', 'Zhongxian', 'Kaixian', 'Yunyang', 'Fengjie', 'Wushan', 'Wuxi', 'Shizhu', 'Xiushan', 'Youyang', 'Pengshui'],
// Otros datos de provincias y ciudades se mantienen de manera similar...
"Guangdong": ['Guangzhou', 'Shaoguan', 'Shenzhen', 'Zhuhai', 'Shantou', 'Foshan', 'Jiangmen', 'Zhanjiang', 'Maoming', 'Zhaoqing', 'Huizhou', 'Meizhou', 'Shanwei', 'Heyuan', 'Yangjiang', 'Qingyuan', 'Dongguan', 'Zhongshan', 'Chaozhou', 'Jieyang', 'Yunfu']
};
// Poblar el menú de provincias
function populateProvinces() {
for (const province of Object.keys(regionData)) {
const optionElement = document.createElement('option');
optionElement.textContent = province;
provinceDropdown.appendChild(optionElement);
}
}
// Actualizar menú de ciudades según provincia seleccionada
provinceDropdown.addEventListener('change', function() {
cityDropdown.innerHTML = ''; // Limpiar opciones actuales
const selectedProvince = provinceDropdown.value;
const cities = regionData[selectedProvince] || [];
cities.forEach(function(city) {
const cityOption = document.createElement('option');
cityOption.textContent = city;
cityDropdown.appendChild(cityOption);
});
});
// Inicializar provincias al cargar la página
populateProvinces();
3. Envío de datos al back end mediante AJAX
Se utiliza una función JavaScript que recopila los valores seleccionados de provincia y ciudad, y los envía al servidor Django a través de una solicitud POST. La URL debe coincidir con la definida en las rutas de Django.
function sendUpdatedData() {
const provinceValue = provinceDropdown.value;
const cityValue = cityDropdown.value;
// Enviar datos al servidor usando AJAX (asumiendo jQuery disponible)
$.ajax({
url: "{% url 'update_vehicle_location' %}", // URL definida en Django
type: "POST",
contentType: "application/json",
data: JSON.stringify({
province: provinceValue,
city: cityValue,
// Otros datos relevantes si es necesario
}),
success: function(response) {
alert(response.message); // Mostrar mensaje de éxito
},
error: function(error) {
console.error("Error al guardar:", error);
}
});
}
En el archivo urls.py de Django, se define la ruta correspondiente:
from django.urls import path
from . import views
urlpatterns = [
path('update_vehicle_location/', views.update_vehicle_location, name='update_vehicle_location'),
// Otras rutas...
]
4. Vista de Django para procesar los datos
La vista en Django recibe la solicitud AJAX, extrae los datos enviados, y actualiza el modelo correspondiente. Se manejan excepciones para devolver respuestas adecuadas.
import json
from django.http import JsonResponse
from .models import VehicleLocation # Modelo hipotético
def update_vehicle_location(request):
"""
Actualiza la información de ubicación (provincia/ciudad) del vehículo.
"""
if request.method == 'POST' and request.is_ajax():
try:
data = json.loads(request.body)
vehicle_id = data.get('vehicle_id') # Asumiendo que el ID se envía
new_province = data.get('province')
new_city = data.get('city')
# Buscar y actualizar el registro en la base de datos
vehicle = VehicleLocation.objects.get(pk=vehicle_id)
if new_province:
vehicle.province = new_province
if new_city:
vehicle.city = new_city
vehicle.save()
return JsonResponse({
'status': 'success',
'message': 'Datos actualizados correctamente.'
})
except Exception as e:
return JsonResponse({
'status': 'error',
'message': str(e)
}, status=400)
else:
return JsonResponse({
'status': 'error',
'message': 'Método no permitido.'
}, status=405)
Esta vista verifica el método de solicitud y si es AJAX, procesa los datos JSON. Actualiza los campos en el modelo VehicleLocation y devuelve una respuesta JSON con el estado de la operación. Los errores se capturan y se devuelven con códigos HTTP apropiados.