Django视图模板URL关联异常:访问model页触发UUID验证错误
Django URL路由冲突导致UUID验证错误排查与解决
问题背景
我有两个产品展示页面:main usage和main model,对应的视图代码如下:
def get_common_queryset(): usage_queryset = Usage.objects.all() sub_usage_queryset = SubUsage.objects.all() main_model_queryset = MainModel.objects.all() pump_type_queryset = PumpType.objects.all() queryset_dictionary = { "usage_queryset": usage_queryset, "sub_usage_queryset": sub_usage_queryset, "main_model_queryset": main_model_queryset, "pump_type_queryset": pump_type_queryset, } return queryset_dictionary def products_usage_main(request): queryset_dictionary = get_common_queryset() context = queryset_dictionary return render(request, "products/products_usage_main.html", context) def products_model_main(request): queryset_dictionary = get_common_queryset() context = queryset_dictionary return render(request, "products/products_model_main.html", context)
get_common_queryset()用于提供公共查询集,两个视图仅渲染的模板不同。
URL配置:
urlpatterns = [ path("application/", products_usage_main, name="products_usage_main"), path("model/", products_model_main, name="products_model_main"), ]
问题现象
点击/products/application/链接可正常访问,但点击/products/model/时抛出以下错误:
ValidationError at /products/model/ ['“model” is not a valid UUID.']
错误追溯指向product_detail视图中的product = Product.objects.get(id=pk)行,该视图代码:
def product_detail(request, pk): product = Product.objects.get(id=pk) head_flow_dataset = HeadFlowDataSet.objects.filter( product=product ).order_by("flow") context_of_view = { "product": product, "head_flow_dataset_x": [], "head_flow_dataset_y": [], } for head_flow in head_flow_dataset: context_of_view["head_flow_dataset_x"].append(head_flow.flow) context_of_view["head_flow_dataset_y"].append(head_flow.head) queryset_dictionary = get_common_queryset() context = { **context_of_view, **queryset_dictionary, } return render(request, "products/product_detail.html", context)
完整错误回溯:
Internal Server Error: /products/model/ Traceback (most recent call last): File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\db\models\fields\__init__.py", line 2649, in to_python return uuid.UUID(**{input_form: value}) File "C:\Users\Vahid Moradi\AppData\Local\Programs\Python\Python310\lib\uuid.py", line 177, in __init__ raise ValueError('badly formed hexadecimal UUID string') ValueError: badly formed hexadecimal UUID string During handling of the above exception, another exception occurred: Traceback (most recent call last): File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\core\handlers\exception.py", line 55, in inner response = get_response(request) File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\products\views.py", line 152, in product_detail product = Product.objects.get(id=pk) File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\db\models\manager.py", line 85, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\db\models\query.py", line 636, in get clone = self._chain() if self.query.combinator else self.filter(*args, **kwargs) File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\db\models\query.py", line 1420, in filter return self._filter_or_exclude(False, args, kwargs) File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\db\models\query.py", line 1438, in _filter_or_exclude clone._filter_or_exclude_inplace(negate, args, kwargs) File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\db\models\query.py", line 1445, in _filter_or_exclude_inplace self._query.add_q(Q(*args, **kwargs)) File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\db\models\sql\query.py", line 1532, in add_q clause, _ = self._add_q(q_object, self.used_aliases) File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\db\models\sql\query.py", line 1562, in _add_q child_clause, needed_inner = self.build_filter( File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\db\models\sql\query.py", line 1478, in build_filter condition = self.build_lookup(lookups, col, value) File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\db\models\sql\query.py", line 1303, in build_lookup lookup = lookup_class(lhs, rhs) File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\db\models\lookups.py", line 27, in __init__ self.rhs = self.get_prep_lookup() File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\db\models\lookups.py", line 341, in get_prep_lookup return super().get_prep_lookup() File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\db\models\lookups.py", line 85, in get_prep_lookup return self.lhs.output_field.get_prep_value(self.rhs) File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\db\models\fields\__init__.py", line 2633, in get_prep_value return self.to_python(value) File "D:\Projects\Navid Motor\Website\Django\NavidMotor.com\.venv\lib\site-packages\django\db\models\fields\__init__.py", line 2651, in to_python raise exceptions.ValidationError( django.core.exceptions.ValidationError: ['“model” is not a valid UUID.'] [12/Dec/2022 11:22:53] "GET /products/model/ HTTP/1.1" 500 145337
原因分析
Django的URL路由是从上到下匹配的,问题出在product_detail的URL配置顺序上。假设你的product_detail路由是类似这样的:
path("<uuid:pk>/", product_detail, name="product_detail"),
如果这条路由放在了path("model/", ...)的前面,那么当访问/products/model/时,Django会把model当作UUID格式的pk参数传递给product_detail视图,但model显然不是合法的UUID,因此抛出验证错误。
而/products/application/能正常访问,是因为没有和它冲突的路由规则在前面匹配到。
解决方案
调整URL路由的顺序,把精确匹配的路由放在动态参数路由的前面,确保model/和application/先被匹配:
urlpatterns = [ # 精确匹配的路由放在前面 path("application/", products_usage_main, name="products_usage_main"), path("model/", products_model_main, name="products_model_main"), # 动态参数路由放在后面 path("<uuid:pk>/", product_detail, name="product_detail"), ]
这样当访问/products/model/时,Django会优先匹配到products_model_main视图,而不是错误地进入product_detail视图。
内容的提问来源于stack exchange,提问作者Vahid
相关产品推荐
相关产品推荐

