Django点击Category出现NoReverseMatch错误的原因排查
Django分类导航报错:Reverse for 'category_2' with arguments '('',)' not found
需求场景
要实现的功能流程:
- 点击页面顶部导航栏的「Category」,展示所有可用分类
- 点击单个分类,显示该分类下的所有商品
- 点击商品名称,进入对应商品的详情页
但第一步点击「Category」时触发错误,错误信息如下:
Request Method: GET Request URL: http://127.0.0.1:8000/category Exception Type: NoReverseMatch at /category Exception Value: Reverse for 'category_2' with arguments '('',)' not found. 1 pattern(s) tried: ['category_2/(?P<cat_id>[0-9]+)/\\Z']
相关代码
views.py
def product_detail(request, product_id): product = get_object_or_404(Product, pk=product_id) comments = Comment.objects.filter(product=product) offers = PriceOffer.objects.filter(product=product).order_by('-offer_price') off_list = [float(product.first_bid)] maximum = float(product.first_bid) if request.method == 'POST': # comment逻辑 # offer逻辑 context = { 'product': product, 'comments': comments, 'offers': offers, 'off' : off } return render(request, 'auctions/product_detail.html', context) def category(request): categories = Category.objects.all() return render(request, 'auctions/category.html', {'categories': categories}) def category_2(request,cat_id): category = Category.objects.get(id=cat_id) products = Product.objects.filter(category=category) return render(request, 'auctions/product_detail.html', {'category': category, 'products': products})
urls.py
path("product_detail/<int:product_id>/", views.product_detail, name="product_detail"), path("category", views.category, name="category"), path("category_2/<int:cat_id>/", views.category_2, name="category_2"),
category.html
{% extends "auctions/layout.html" %} {% block body %} <h2>All Categories</h2> {% for category in categories %} <h3><a href="{% url 'category_2' category.pk %}">{{ category.name }}</a></h3> {% endfor %} {% endblock %}
product_detail.html(相关部分)
<h2>{{ category.name }}</h2> {% for product in products %} <h3>{{ product.name }}</h3> {% endfor %}
layout.html(顶部导航部分)
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <title>{% block title %}Auctions{% endblock %}</title> </head> <body> <h1>Auctions</h1> <div> {% if user.is_authenticated %} Signed in as <strong>{{ user.username }}</strong>. {% else %} Not signed in. {% endif %} </div> <ul class="nav"> <li class="nav-item"> <a class="nav-link" href="{% url 'index' %}">Active Listings</a> </li> <li class="nav-item"> <a class="nav-link" href="{% url 'category' %}">Category</a> </li> {% if user.is_authenticated %} <li class="nav-item"> <a class="nav-link" href="{% url 'logout' %}">Log Out</a> </li> {% else %} <li class="nav-item"> <a class="nav-link" href="{% url 'login' %}">Log In</a> </li> <li class="nav-item"> <a class="nav-link" href="{% url 'register' %}">Register</a> </li> {% endif %} </ul> <hr> {% block body %} {% endblock %} </body>
错误原因
报错核心是循环中的某个category对象的pk为空字符串,模板执行{% url 'category_2' category.pk %}时,无法生成符合要求的URL——因为category_2路由要求传入整数类型的cat_id,空字符串不匹配路由规则。
可能的触发点:
- 数据库中存在
id(主键)为空的Category无效记录 - 分类查询时意外获取到了未初始化的空对象
解决方案
1. 清理无效分类数据
检查数据库中的Category表,删除或修复id为空的无效记录,确保所有分类都有合法的主键值。
2. 模板增加空值过滤
在category.html的循环中,先判断category.pk是否存在,再渲染链接,避免生成无效URL:
{% extends "auctions/layout.html" %} {% block body %} <h2>所有分类</h2> {% for category in categories %} {% if category.pk %} <h3><a href="{% url 'category_2' category.pk %}">{{ category.name }}</a></h3> {% endif %} {% endfor %} {% endblock %}
3. 视图层提前过滤无效数据
在category视图中,提前排除无主键的分类,避免无效数据传入模板:
def category(request): # 只保留有有效主键的分类 categories = Category.objects.exclude(id__isnull=True) return render(request, 'auctions/category.html', {'categories': categories})
4. 修复category_2视图的异常处理
当前category_2视图用Category.objects.get(id=cat_id),如果传入的cat_id不存在会抛出DoesNotExist错误,建议改用get_object_or_404返回404页面,避免服务器崩溃:
from django.shortcuts import get_object_or_404 def category_2(request, cat_id): category = get_object_or_404(Category, id=cat_id) products = Product.objects.filter(category=category) # 建议创建单独的分类商品列表模板,避免和商品详情页模板混淆 return render(request, 'auctions/category_products.html', {'category': category, 'products': products})
额外优化建议
- 模板分离:分类商品列表和商品详情页应使用不同模板,避免变量冲突(当前用product_detail.html同时处理两种场景,容易引发逻辑混乱)
- 路由命名优化:将
category_2改为更语义化的名称,比如category_products,提升代码可读性 - 商品跳转链接:在分类商品列表中,给商品名称添加跳转详情页的链接,完成完整流程:
{% for product in products %} <h3><a href="{% url 'product_detail' product.pk %}">{{ product.name }}</a></h3> {% endfor %}
内容的提问来源于stack exchange,提问作者zahra
相关产品推荐
相关产品推荐

