转发到另一个视图会吞下一个参数

Forwarding to another view swallows one argument

我有一个 ListView 检查用户权限并根据用户权限转发查询集或重定向到另一个视图:

class SelectQualityListView(StoreMixin, ListView):
    template_name = f"{TEMPLATE_ROOT_SHELF}/select_register.html"

    def get_queryset(self):
        registers = Register.objects.filter(store = self.store)
        print(registers, registers.first().pk) ## works ... and 4
        if check_custom_registers_allowed(self.request) == True:
            return registers
        return redirect("select-quality", ins_id = self.kwargs["ins_id"], pg = self.kwargs["pg"], reg = registers.first().pk)

我的urls.py里有这个:

path("selectquality/<int:ins_id>/<int:pg>/<int:reg>", views.SelectQualityListView.as_view(), name = 'select-quality'),

失败并出现 NoReverseMatch 错误:

Reverse for 'select-quality' with keyword arguments '{'ins_id': 1849332, 'pg': 3, 'reg': ''}' not found.

我现在尝试了不同的值而不是 registers.first().pk,我需要帮助来理解这一点:

添加 int -> reg 保持为空 - 添加 str(4)

时也会发生

return redirect("select-quality", ins_id = self.kwargs["ins_id"], pg = self.kwargs["pg"], reg = 4)

Reverse for 'select-quality' with keyword arguments '{'ins_id': 1849332, 'pg': 3, 'reg': ''}' not found.

添加 str -> reg 有值,但失败

return redirect("select-quality", ins_id = self.kwargs["ins_id"], pg = self.kwargs["pg"], reg = "test")

Reverse for 'select-quality' with keyword arguments '{'ins_id': 1849332, 'pg': 3, 'reg': 'test'}' not found.

最后一种情况很明显,reg需要是int类型,而不是str。但为什么第一种方法不适用于 reg = registers.first().pk

完整错误日志:

Internal Server Error: /selectquality/1849332/3
Traceback (most recent call last):
  File "...\venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
  File "...\venv\lib\site-packages\django\core\handlers\base.py", line 204, in _get_response
    response = response.render()
  File "...\venv\lib\site-packages\django\template\response.py", line 105, in render
    self.content = self.rendered_content
  File "...\venv\lib\site-packages\django\template\response.py", line 83, in rendered_content
    return template.render(context, self._request)
  File "...\venv\lib\site-packages\django\template\backends\django.py", line 61, in render
    return self.template.render(context)
  File "...\venv\lib\site-packages\django\template\base.py", line 170, in render
    return self._render(context)
  File "...\venv\lib\site-packages\django\template\base.py", line 162, in _render
    return self.nodelist.render(context)
  File "...\venv\lib\site-packages\django\template\base.py", line 938, in render
    bit = node.render_annotated(context)
  File "...\venv\lib\site-packages\django\template\base.py", line 905, in render_annotated
    return self.render(context)
  File "...\venv\lib\site-packages\django\template\defaulttags.py", line 211, in render
    nodelist.append(node.render_annotated(context))
  File "...\venv\lib\site-packages\django\template\base.py", line 905, in render_annotated
    return self.render(context)
  File "...\venv\lib\site-packages\django\template\defaulttags.py", line 446, in render
    url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app)
  File "...\venv\lib\site-packages\django\urls\base.py", line 86, in reverse
    return resolver._reverse_with_prefix(view, prefix, *args, **kwargs)
  File "...\venv\lib\site-packages\django\urls\resolvers.py", line 698, in _reverse_with_prefix
    raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'select-quality' with arguments '(1849332, 3, '')' not found. 4 pattern(s) tried: 
['selectquality/(?P<ins_id>[0-9]+)/(?P<pg>[0-9]+)/(?P<reg>[0-9]+)/(?P<prod1>[0-9]+)\Z', 
'selectquality/(?P<ins_id>[0-9]+)/(?P<pg>[0-9]+)/(?P<reg>[0-9]+)/(?P<prod1>[0-9]+)/(?P<prod2>[0-9]+)\Z', 
'selectquality/(?P<ins_id>[0-9]+)/(?P<pg>[0-9]+)/(?P<reg>[0-9]+)/(?P<prod1>[0-9]+)/(?P<prod2>[0-9]+)/(?P<prod3>[0-9]+)\Z', 
'selectquality/(?P<ins_id>[0-9]+)/(?P<pg>[0-9]+)/(?P<reg>[0-9]+)\Z']

urls.py 的:

path("selectquality/<int:ins_id>/<int:pg>/<int:reg>",                 views.SelectQualityListView.as_view(), name = 'select-quality'),
path("selectquality/<int:ins_id>/<int:pg>/<int:reg>/<int:p1>/<int:p2>/<int:p3>",     views.SelectQualityListView.as_view(), name = 'select-quality'),
path("selectquality/<int:ins_id>/<int:pg>/<int:reg>/<int:p1>/<int:p2>",     views.SelectQualityListView.as_view(), name = 'select-quality'),
path("selectquality/<int:ins_id>/<int:pg>/<int:reg>/<int:p1>",     views.SelectQualityListView.as_view(), name = 'select-quality'),

有趣的是,我的模板中的这些链接可以正常工作:

{% url 'select-quality' ins_id pg reg.pk %}

在 ListView 中,方法 get_query_set() 用于定义更复杂的查询,应该执行这些查询以缩小视图中列出的模型元素的范围。这是来自 django 文档的示例 https://docs.djangoproject.com/en/4.0/ref/class-based-views/generic-display/#listview:

class PublisherBookListView(ListView):

    template_name = 'books/books_by_publisher.html'

    def get_queryset(self):
        self.publisher = get_object_or_404(Publisher, name=self.kwargs['publisher'])
        return Book.objects.filter(publisher=self.publisher)

所以 get_queryset 必须总是 return 一个查询集。

在 GET-request 期间,此 returned 查询集用于通过 get() 方法呈现 ListView 的内容,html-template 定义为“template_name”。对于渲染步骤,查询集被添加到渲染上下文中。

如果像您的情况一样,您 return 一个“重定向”HTTPResponse 并将其作为“queryset”移交,任何结果都可能取决于您的 html-template。

如果您想对查询集做出反应,请覆盖 get() 方法,调用 get_queryset(),进行检查并从那里重定向。在 get_queryset() 中只做基本查询。

class SelectQualityListView(StoreMixin, ListView):
    template_name = f"{TEMPLATE_ROOT_SHELF}/select_register.html"

    def get_queryset(self):
        return Register.objects.filter(store = self.store)

    def get(self, request, *args, **kwargs):
        if check_custom_registers_allowed(self.request) is not True:
           return redirect("select-quality", ins_id = self.kwargs["ins_id"], pg = self.kwargs["pg"], reg = registers.first().pk)
        super().get(request, *args, **kwargs)

注意:这只是为了展示想法......他们可能是代码中的错误