-1

I'm trying to build a simple app that collects data on shoes and then displays it as a list. I want to use pagination, which is pretty simple using Django's paginator. My problem is that I cannot get Django to give me the value sent in a GET request.

According to Django docs what I have been doing should work. I've tried it with request and HttpRequest and every time I get a a "no attribute" error.


    Traceback (most recent call last):
      File "/usr/lib/python3.9/threading.py", line 954, in _bootstrap_inner
        self.run()
      File "/usr/lib/python3.9/threading.py", line 892, in run
        self._target(*self._args, **self._kwargs)
      File "/home/pjay/PycharmProjects/gettest/venv/lib/python3.9/site-packages/django/utils/autoreload.py", line 64, in wrapper
        fn(*args, **kwargs)
      File "/home/pjay/PycharmProjects/gettest/venv/lib/python3.9/site-packages/django/core/management/commands/runserver.py", line 118, in inner_run
        self.check(display_num_errors=True)
      File "/home/pjay/PycharmProjects/gettest/venv/lib/python3.9/site-packages/django/core/management/base.py", line 419, in check
        all_issues = checks.run_checks(
      File "/home/pjay/PycharmProjects/gettest/venv/lib/python3.9/site-packages/django/core/checks/registry.py", line 76, in run_checks
        new_errors = check(app_configs=app_configs, databases=databases)
      File "/home/pjay/PycharmProjects/gettest/venv/lib/python3.9/site-packages/django/core/checks/urls.py", line 13, in check_url_config
        return check_resolver(resolver)
      File "/home/pjay/PycharmProjects/gettest/venv/lib/python3.9/site-packages/django/core/checks/urls.py", line 23, in check_resolver
        return check_method()
      File "/home/pjay/PycharmProjects/gettest/venv/lib/python3.9/site-packages/django/urls/resolvers.py", line 412, in check
        for pattern in self.url_patterns:
      File "/home/pjay/PycharmProjects/gettest/venv/lib/python3.9/site-packages/django/utils/functional.py", line 48, in __get__
        res = instance.__dict__[self.name] = self.func(instance)
      File "/home/pjay/PycharmProjects/gettest/venv/lib/python3.9/site-packages/django/urls/resolvers.py", line 598, in url_patterns
        patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
      File "/home/pjay/PycharmProjects/gettest/venv/lib/python3.9/site-packages/django/utils/functional.py", line 48, in __get__
        res = instance.__dict__[self.name] = self.func(instance)
      File "/home/pjay/PycharmProjects/gettest/venv/lib/python3.9/site-packages/django/urls/resolvers.py", line 591, in urlconf_module
        return import_module(self.urlconf_name)
      File "/usr/lib/python3.9/importlib/__init__.py", line 127, in import_module
        return _bootstrap._gcd_import(name[level:], package, level)
      File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
      File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
      File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
      File "<frozen importlib._bootstrap_external>", line 855, in exec_module
      File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
      File "/home/pjay/PycharmProjects/gettest/gettest/gettest/urls.py", line 21, in <module>
        path('', include('shoes.urls'), name='shoes_list'),
      File "/home/pjay/PycharmProjects/gettest/venv/lib/python3.9/site-packages/django/urls/conf.py", line 34, in include
        urlconf_module = import_module(urlconf_module)
      File "/usr/lib/python3.9/importlib/__init__.py", line 127, in import_module
        return _bootstrap._gcd_import(name[level:], package, level)
      File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
      File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
      File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
      File "<frozen importlib._bootstrap_external>", line 855, in exec_module
      File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
      File "/home/pjay/PycharmProjects/gettest/gettest/shoes/urls.py", line 3, in <module>
        from . import views
      File "/home/pjay/PycharmProjects/gettest/gettest/shoes/views.py", line 7, in <module>
        class ShoeListView(ListView):
      File "/home/pjay/PycharmProjects/gettest/gettest/shoes/views.py", line 11, in ShoeListView
        if request.method == "GET":
    AttributeError: module 'django.http.request' has no attribute 'method'

The following is the code I have in my views.py file.

from django.views.generic import ListView
from django.http import HttpRequest, request

from .models import Shoes


class ShoeListView(ListView):
    model = Shoes
    template_name = 'shoes/shoes-list.html'
    context_object_name = 'shoes'
    if request.method == "GET":
        shoespp = request.GET['shoespp']
    else:
        shoespp = 2
    paginate_by = shoespp

And this is my template.

<body>
    <h1>Shoes</h1>
    <h2>List of Shoes</h2>
    <form method="get">
        <select name="shoespp">
            <option value="2">2</option>
            <option value="3">3</option>
            <option value="4">4</option>
        </select>
        <input type="submit" value="List Shoes">
    </form>

    <ul>
        {%for pair in shoes %}
        <li>
            <strong>{{ pair }} <em>{{ pair.brand }}</em></strong> <em>{{ pair.colorway }}</em> - {{ pair.size }}
        </li>
        {% endfor %}
    </ul>

    <p>
        {% if page_obj.has_previous %}
        <a href="?page=1"><button>&laquo; first</button></a>
        <a href="?page={{ page_obj.previous_page_number }}"><button>previous</button></a>
        {% endif %}

        <span>
            Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
        </span>

        {% if page_obj.has_next %}
        <a href="?page={{ page_obj.next_page_number }}"><button>next</button></a>
        <a href="?page={{ page_obj.paginator.num_pages }}"><button>last &raquo; </button></a>
        {% endif %}
    </p>
</body>

Can anyone point me to where I'm going wrong here? I'm all out of ideas, and have searched unsuccessfully for a possible answer. Thanks in advance.

Edit (with solution code)

Thanks to @furas for providing the solution to my problem. I think I now understand what went wrong. I'm providing the solution code for anyone who might stumble upon this with a similar issue.

views.py

    from django.views.generic import ListView
    
    from .models import Shoes
    
    
    class ShoeListView(ListView):
        model = Shoes
        template_name = 'shoes/shoes-list.html'
        context_object_name = 'shoes'
        paginate_by = 1
    
        def get_context_data(self, **kwargs):
            if 'shoespp' in self.request.GET:
                self.paginate_by = self.request.GET.get('shoespp', 2)
            shoes = super().get_context_data(**kwargs)
            shoes['last_shoespp'] = self.request.GET.get('shoespp')
            return shoes

template_file.html

    <!DOCTYPE html>
    <html lang="en-au">
        <head>
            <title>Shoes List</title>
        </head>
    
        <body>
            <h1>Shoes</h1>
            <h2>List of Shoes</h2>
            <form method="GET">
                <select name="shoespp" action="">
                    <option value="2">2</option>
                    <option value="3">3</option>
                    <option value="4">4</option>
                </select>
                <input type="submit" value="List Shoes">
            </form>
    
            <h3>{{ shoespp }}</h3>
    
            <ul>
                {%for pair in shoes %}
                <li>
                    <strong>{{ pair }} <em>{{ pair.brand }}</em></strong> <em>{{ pair.colorway }}</em> - {{ pair.size }}
                </li>
                {% endfor %}
            </ul>
    
            <h3>{{ steps }}</h3>
    
            <p>
                {% if page_obj.has_previous %}
                <a href="?page=1{% if 'last_shoespp' != False %}&shoespp={{ last_shoespp }}{% endif %}">
                    <button>&laquo; first</button>
                </a>
                <a href="?page={{ page_obj.previous_page_number }}{% if 'last_shoespp' != False %}&shoespp={{ last_shoespp }}{% endif %}">
                    <button>previous</button>
                </a>
                {% endif %}
    
                <span>
                    Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
                </span>
    
                {% if page_obj.has_next %}
                <a href="?page={{ page_obj.next_page_number }}{% if 'last_shoespp' != False %}&shoespp={{ last_shoespp }}{% endif %}">
                    <button>next</button>
                </a>
                <a href="?page={{ page_obj.paginator.num_pages }}{% if 'last_shoespp' != False %}&shoespp={{ last_shoespp }}{% endif %}">
                    <button>last &raquo;</button>
                </a>
                {% endif %}
            </p>
        </body>
    </html>
PJay_D
  • 11
  • 1
  • 2
  • always put full error message (starting at word "Traceback") in question (not comment) as text (not screenshot, not link to external portal). There are other useful information. – furas Oct 07 '21 at 03:02
  • your pagination has only `?page=... ` but not `?shoespp=...` -- you may need `?page= ...&shoespp=...`. At this moment It should send `shoespp` only if you click `List Shoes` – furas Oct 07 '21 at 03:06
  • `request.GET` is a dictionary and you can always use `request.GET.get('shoespp', 2)` to get `2` when there is no `shoespp` in request. – furas Oct 07 '21 at 03:10
  • Thank you @furas I've made the edit to my post. The issue is that I get the error when I try to get the GET data in the "usual" manner. – PJay_D Oct 07 '21 at 04:22
  • important is if you get error when you click `List Shoes` or link to next/previous page. Link to next/previouse page doesn't have `shoespp` so you can't get it in code. You have to add `&shoespp=...` to every links in pagination. – furas Oct 07 '21 at 04:40
  • Thanks @furas The issue is that I get that error before I can even run the code. I now found that with 'request = HttpRequest()' I get around that but still no luck. I can see in the terminal that a GET response has been sent but the code tells me that GET is a Null object as the 'request.method == "GET"' test is negative. – PJay_D Oct 07 '21 at 05:02
  • now I see, you should put code in some function inside `ShoeListView`, not directly in class. If you have it directly in class then it is executed when you start Django, not when you send data from browser to server. It may be `def get_queryset(self): ...` – furas Oct 07 '21 at 05:05
  • BTW: I would use `shoespp` as `filter`, not `pagination` – furas Oct 07 '21 at 05:12
  • error shows that problem makes `requests.method` not `requests.GET` - and when I look on some examples on internet then I think it should be `self.request` instead of `request` - so it will be use internal value `self.request` instead of `django.http.request` – furas Oct 07 '21 at 05:36

1 Answers1

1

At your current code it executes request.GET at start - before it even sends HTML to browser and use can click on List shoes.

I think it should be in some function which is executed when server get request from browser.

But other problem can be that this page sends GET using <form> but also every links in pagination is send as GET so you may have to check if shoespp was really send.

I can't test it but it can be something like this

class ShoeListView(ListView):
    model = Shoes
    template_name = 'shoes/shoes-list.html'
    context_object_name = 'shoes'

    paginate_by = 2  # set some value at start

    def get_context_data(self, **kwargs):
        # change value when get new value from browser
        if 'shoespp' in self.request.GET:
             self.paginate_by = self.request.GET.get('shoespp', 2)

        context = super().get_context_data(**kwargs)

        return context


See also code in second answer for question How do I use pagination with Django class based generic ListViews?

furas
  • 134,197
  • 12
  • 106
  • 148