Django电商网站过滤后商品无法在模板渲染的问题
问题描述
开发电商网站筛选功能时,通过JSON获取筛选参数,在views.py中过滤商品。控制台能正常输出过滤后的商品结果且无报错,但模板无法渲染显示这些商品。
相关代码
views.py
def Products(request): data = cartData(request) cartItems = data['cartItems'] order = data['order'] items = data['items'] products = Product.objects.all() gender = Gender.objects.all() categories = Category.objects.all() product_types = ProductType.objects.all() try: data = json.loads(request.body) productTId = data['productTId'] productVId = data['productVId'] genderId = data['genderId'] genderId = get_object_or_404(Gender, id=genderId) productVId = get_object_or_404(Category, id=productVId) productTId = get_object_or_404(ProductType, id=productTId) filtered_products = Product.objects.filter(typeP=productTId).filter(category=productVId).filter(Gender=genderId) countFilter=filtered_products.count() print(filtered_products) print(countFilter) return JsonResponse(filtered_products, safe = False) except: None try: context = {'countFilter':countFilter,'filtered_products':filtered_products,'gender':gender,'categories':categories,'product_types':product_types,'products':products, 'cartItems':cartItems, 'order':order, 'items':items} except: context = {'gender':gender,'categories':categories,'product_types':product_types,'products':products, 'cartItems':cartItems, 'order':order, 'items':items} return render(request, 'product.html', context)
HTML模板
{% for product in filtered_products %} <div class="card"> <div class="card__img"> <picture><source srcset="{{product.imageURL}}" type="image/webp"><img src="{{product.imageURL}}" alt=""></picture> </div> <h6 class="card__title">{{product.name}}</h6> <div class="card__descr">{{product.description}}... <div class="card__more" onclick="More('{{product.id}}')">подробнее...</div> </div> <div class="card__func"> <a class="btn-hover card__button-buy update-cart" data-product="{{product.id}}" data-action="add">В КОРЗИНУ</a> <div class="card__right"> <div class="card__price" data-product="{{product.id}}">{{product.price}} р</div> <div class="card__changed-price card__changed-price--card"> <div class="card__changed-btn card__changed-btn--prev card__changed-btn--max increase" data-product="{{product.id}}" data-action="minus"><svg width="8" height="2" viewBox="0 0 8 2" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M1 1L7 1" stroke="#7ABC51" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> <p class="card__changed-thing" id="quantity" class="quantity" data-product="{{product.id}}">1</p> <div class="card__changed-btn card__changed-btn--next increase" data-product="{{product.id}}" data-action="plus"><svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" clip-rule="evenodd" d="M3 7C3 7.41421 3.33579 7.75 3.75 7.75C4.16421 7.75 4.5 7.41421 4.5 7V4.75H6.75C7.16421 4.75 7.5 4.41421 7.5 4C7.5 3.58579 7.16421 3.25 6.75 3.25H4.5V1C4.5 0.585786 4.16421 0.25 3.75 0.25C3.33579 0.25 3 0.585786 3 1V3.25H0.75C0.335786 3.25 0 3.58579 0 4C0 4.41421 0.335786 4.75 0.75 4.75H3V7Z" fill="#7ABC51"/> </svg> </div> </div> </div> </div> </div> {% endfor %}
核心问题分析
- 提前终止视图执行:当成功解析JSON参数后,直接返回
JsonResponse,视图函数会立即停止,不会执行后续渲染模板的代码。前端拿到JSON数据,但没有对应的JS逻辑更新DOM,所以看不到商品。 - 异常处理过于宽泛:
except: None会捕获所有异常,包括变量未定义的情况,导致后续try块引用filtered_products和countFilter时触发异常,进入默认context,模板中没有filtered_products变量,循环不执行。 - 请求逻辑混淆:如果是AJAX请求,需要前端配合更新页面;如果是普通表单提交,不该用
json.loads(request.body)获取参数。
解决方案
方案1:适配AJAX请求(推荐)
如果前端通过AJAX发送筛选请求,需要视图返回结构化JSON,再由JS动态更新页面。
修改后的views.py
def Products(request): data = cartData(request) cartItems = data['cartItems'] order = data['order'] items = data['items'] products = Product.objects.all() gender = Gender.objects.all() categories = Category.objects.all() product_types = ProductType.objects.all() # 识别AJAX请求 if request.headers.get('X-Requested-With') == 'XMLHttpRequest': try: data = json.loads(request.body) productTId = data['productTId'] productVId = data['productVId'] genderId = data['genderId'] gender_obj = get_object_or_404(Gender, id=genderId) category_obj = get_object_or_404(Category, id=productVId) type_obj = get_object_or_404(ProductType, id=productTId) filtered_products = Product.objects.filter(typeP=type_obj, category=category_obj, Gender=gender_obj) countFilter = filtered_products.count() # 序列化商品数据为JSON可解析格式 product_list = list(filtered_products.values('id', 'name', 'description', 'price', 'imageURL')) return JsonResponse({ 'countFilter': countFilter, 'filtered_products': product_list }) except Exception as e: print(f"AJAX处理异常: {e}") return JsonResponse({'error': str(e)}, status=400) # 非AJAX请求,渲染初始页面 context = { 'gender': gender, 'categories': categories, 'product_types': product_types, 'products': products, 'cartItems': cartItems, 'order': order, 'items': items } return render(request, 'product.html', context)
前端添加JS逻辑
在模板中加入以下代码,处理AJAX响应并更新DOM:
// 绑定筛选表单提交事件 document.getElementById('filter-form').addEventListener('submit', function(e) { e.preventDefault(); const productTId = document.getElementById('product-type').value; const productVId = document.getElementById('category').value; const genderId = document.getElementById('gender').value; fetch('/products/', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') }, body: JSON.stringify({ productTId: productTId, productVId: productVId, genderId: genderId }) }) .then(response => response.json()) .then(data => { const productContainer = document.getElementById('product-container'); productContainer.innerHTML = ''; // 动态生成商品卡片 data.filtered_products.forEach(product => { const card = ` <div class="card"> <div class="card__img"> <picture><source srcset="${product.imageURL}" type="image/webp"><img src="${product.imageURL}" alt=""></picture> </div> <h6 class="card__title">${product.name}</h6> <div class="card__descr">${product.description}... <div class="card__more" onclick="More('${product.id}')">подробнее...</div> </div> <div class="card__func"> <a class="btn-hover card__button-buy update-cart" data-product="${product.id}" data-action="add">В КОРЗИНУ</a> <div class="card__right"> <div class="card__price" data-product="${product.id}">${product.price} р</div> <div class="card__changed-price card__changed-price--card"> <div class="card__changed-btn card__changed-btn--prev card__changed-btn--max increase" data-product="${product.id}" data-action="minus"> <svg width="8" height="2" viewBox="0 0 8 2" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M1 1L7 1" stroke="#7ABC51" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> <p class="card__changed-thing quantity" data-product="${product.id}">1</p> <div class="card__changed-btn card__changed-btn--next increase" data-product="${product.id}" data-action="plus"> <svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" clip-rule="evenodd" d="M3 7C3 7.41421 3.33579 7.75 3.75 7.75C4.16421 7.75 4.5 7.41421 4.5 7V4.75H6.75C7.16421 4.75 7.5 4.41421 7.5 4C7.5 3.58579 7.16421 3.25 6.75 3.25H4.5V1C4.5 0.585786 4.16421 0.25 3.75 0.25C3.33579 0.25 3 0.585786 3 1V3.25H0.75C0.335786 3.25 0 3.58579 0 4C0 4.41421 0.335786 4.75 0.75 4.75H3V7Z" fill="#7ABC51"/> </svg> </div> </div> </div> </div> </div> `; productContainer.innerHTML += card; }); }) .catch(error => console.error('筛选请求失败:', error)); }); // 获取CSRF令牌辅助函数 function getCookie(name) { let cookieValue = null; if (document.cookie && document.cookie !== '') { const cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].trim(); if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; }
方案2:普通表单提交(页面刷新)
如果不需要AJAX,改用普通表单提交参数,视图直接渲染过滤后的页面。
修改后的views.py
def Products(request): data = cartData(request) cartItems = data['cartItems'] order = data['order'] items = data['items'] products = Product.objects.all() gender = Gender.objects.all() categories = Category.objects.all() product_types = ProductType.objects.all() filtered_products = products countFilter = 0 # 从GET参数中获取筛选条件 productTId = request.GET.get('productTId') productVId = request.GET.get('productVId') genderId = request.GET.get('genderId') if productTId and productVId and genderId: try: gender_obj = get_object_or_404(Gender, id=genderId) category_obj = get_object_or_404(Category, id=productVId) type_obj = get_object_or_404(ProductType, id=productTId) filtered_products = Product.objects.filter(typeP=type_obj, category=category_obj, Gender=gender_obj) countFilter = filtered_products.count() except Exception as e: print(f"筛选异常: {e}") context = { 'countFilter': countFilter, 'filtered_products': filtered_products, 'gender': gender, 'categories': categories, 'product_types': product_types, 'products': products, 'cartItems': cartItems, 'order': order, 'items': items } return render(request, 'product.html', context)
修改前端表单
<form method="get" action="/products/"> <select name="productTId" id="product-type"> {% for type in product_types %} <option value="{{ type.id }}">{{ type.name }}</option> {% endfor %} </select> <select name="productVId" id="category"> {% for cat in categories %} <option value="{{ cat.id }}">{{ cat.name }}</option> {% endfor %} </select> <select name="genderId" id="gender"> {% for g in gender %} <option value="{{ g.id }}">{{ g.name }}</option> {% endfor %} </select> <button type="submit">筛选</button> </form> <div id="product-container"> {% for product in filtered_products %} <!-- 商品卡片内容保持不变 --> <div class="card">...</div> {% endfor %} </div>
内容的提问来源于stack exchange,提问作者Behzod Urinov
相关产品推荐
相关产品推荐

