I have a ListView
that checks for a user right and forwards a queryset or redirects to another view depending on the user's rights:
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)
I have this in my urls.py:
path("selectquality/<int:ins_id>/<int:pg>/<int:reg>", views.SelectQualityListView.as_view(), name = 'select-quality'),
which fails with a NoReverseMatch
error:
Reverse for 'select-quality' with keyword arguments '{'ins_id': 1849332, 'pg': 3, 'reg': ''}' not found.
I now tried different values instead of registers.first().pk
and I need help understanding this:
when adding an int -> reg stays empty - also happens when adding 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.
when adding a str -> reg has value, but fails
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.
The last case is obvious, reg
needs to be of type int
, not str
. But why does the first approach not work with reg = registers.first().pk
?
Full Error log:
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 of this:
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'),
Interestingly enough, these links in my template work correctly:
{% url 'select-quality' ins_id pg reg.pk %}
CodePudding user response:
In a ListView the method get_query_set() is used to define more complex queries that should be performed to narrow down the elements of the model listed in the View. Here is the example from django docs 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)
So get_queryset must alwas return a queryset.
During a GET-request, this returned queryset is used to render the content of the ListView via the get() method and the html-template defined as "template_name". For the rendering step, the queryset is added to the render context.
If like in your case you return a "redirect" HTTPResponse and hand it over as "queryset", anything can be the result depending on your html-template.
If you want to react on the queryset, then overwrite the get() method, call get_queryset(), do your checks and redirect from there. Inside the get_queryset() just do the basic query.
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)
note: this is only to show the idea ... their might be mistakes in the code
CodePudding user response:
See if you can run the following and what you get:
from django.urls import reverse
reverse('select-quality', args=(1,2,3))
reverse('select-quality', kwargs={'ins_id': 1, 'pg': 2, 'reg': 3})
If both calls resolve successfully, see what are the types of values you're passing to the redirect call.