Skip to content

AttributeError: 'dict' object has no attribute 'getlist' #1406

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
folt opened this issue Nov 27, 2020 · 9 comments
Closed

AttributeError: 'dict' object has no attribute 'getlist' #1406

folt opened this issue Nov 27, 2020 · 9 comments
Labels

Comments

@folt
Copy link
Contributor

folt commented Nov 27, 2020

when using django-debug-toolbar = 3.1 version I get error

Traceback (most recent call last):
  File "/home/folt/env_work/temes-Yu7Jpmcx-py3.7/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/home/folt/env_work/temes-Yu7Jpmcx-py3.7/lib/python3.7/site-packages/sentry_sdk/integrations/django/middleware.py", line 134, in call
    return f(*args, **kwargs)
  File "/home/folt/env_work/temes-Yu7Jpmcx-py3.7/lib/python3.7/site-packages/sentry_sdk/integrations/django/middleware.py", line 90, in sentry_wrapped_method
    return old_method(*args, **kwargs)
  File "/home/folt/env_work/temes-Yu7Jpmcx-py3.7/lib/python3.7/site-packages/debug_toolbar/middleware.py", line 67, in call
    panel.generate_stats(request, response)
  File "/home/folt/env_work/temes-Yu7Jpmcx-py3.7/lib/python3.7/site-packages/debug_toolbar/panels/request.py", line 30, in generate_stats
    "post": [(k, request.POST.getlist(k)) for k in sorted(request.POST)],
  File "/home/folt/env_work/temes-Yu7Jpmcx-py3.7/lib/python3.7/site-packages/debug_toolbar/panels/request.py", line 30, in <listcomp>
    "post": [(k, request.POST.getlist(k)) for k in sorted(request.POST)],
AttributeError: 'dict' object has no attribute 'getlist'

when using django-debug-toolbar = 2.0 version everything works correctly

[tool.poetry.dependencies]
python = "3.7.8"

django = "^2.2.11"
django-split-settings = "^1.0"
django-feature-policy = "^3.5"

psycopg2 = "^2.8"
gunicorn = "^20.0"
python-decouple = "^3.3"
bcrypt = "^3.2"
structlog = "^20.1.0"
importlib-metadata = "^2.0.0"
django-redis = "^4.12.1"
django-oauth-toolkit = "^1.3.2"
raven = "^6.10.0"
mysqlclient = "^2.0.1"
djongo = "^1.3.3"
djangorestframework = "^3.12.1"
django-filter = "^2.4.0"
django-constance = {extras = ["redis"], version = "^2.7.0"}
celery = "^5.0.1"
firebase-admin = "^4.4.0"
ujson = "^4.0.1"
cryptography = "^3.1.1"
jsonfield = "^3.1.0"
django-threadlocals = "^0.10"
polyline = "^1.4.0"
geopy = "^2.0.0"
clickhouse-driver = "^0.1.5"
AMQPStorm = "^2.8.2"
sentry-sdk = "^0.19.1"
django-phonenumber-field = {extras = ["phonenumbers"], version = "^5.0.0"}
django-extensions = "^3.0.9"
django-sslserver = "^0.22"
drf-yasg2 = "^1.19.3"
tqdm = "^4.50.2"
python-dateutil = "^2.8.1"
uWSGI = "^2.0.19"
django-ipware = "^3.0.2"
geoip2 = "^4.1.0"


[tool.poetry.dev-dependencies]
django-debug-toolbar = "^2.0"
django-querycount = "^0.7"
django-coverage-plugin = "^1.8"
nplusone = "^1.0"

wemake-python-styleguide = "^0.14"
flake8-pytest-style = "^1.3"
flake8-django = "^1.1"
flake8-logging-format = "^0.6"
nitpick = "^0.23"

pytest = "^6.1"
pytest-django = "^3.10"
pytest-cov = "^2.10"
pytest-randomly = "^3.4"
pytest-deadfixtures = "^2.2"
pytest-testmon = "^1.0"
pytest-timeout = "^1.4"
hypothesis = "^5.37"

mypy = "^0.770"
django-stubs = "^1.4"

ipython = "^7.18"

sphinx = "^2.4"
sphinx-autodoc-typehints = "^1.10"
doc8 = "^0.8"

yamllint = "^1.25"
safety = "^1.9"
dotenv-linter = "^0.1"
polint = "^0.4"
dennis = "^0.9"
dump-env = "^1.2"
@matthiask
Copy link
Member

Hi,

this is probably a duplicate of #1150

Maybe django-debug-toolbar shouldn't crash, but the point still stands that request.POST is supposed to be a QueryDict, not a dict instance.

@folt
Copy link
Contributor Author

folt commented Nov 27, 2020

Hi,

this is probably a duplicate of #1150

Maybe django-debug-toolbar shouldn't crash, but the point still stands that request.POST is supposed to be a QueryDict, not a dict instance.

thanks for the answer
is there any progress in fixing this error?

@folt folt added the Bug label Nov 27, 2020
@matthiask
Copy link
Member

No. The argument still is that this isn't a bug in django-debug-toolbar but in your code.

@folt
Copy link
Contributor Author

folt commented Nov 27, 2020

class SmsViewSet(viewsets.GenericViewSet):
    permission_classes = [permissions.AllowAny]

    serializer_action_classes = {
        'create': system_serializers.PhoneSerializer,
    }

    def get_serializer_class(self):
        return self.serializer_action_classes[self.action]

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        return response.Response(status=status.HTTP_204_NO_CONTENT)

    def perform_create(self, serializer):
        serializer.save()
        phone = serializer.instance.recipient.phone.as_e164
        text = f'Activation code: {serializer.instance.sms}'

        if config.DEV_SMS_ON:
            pass
        else:
            common_routee.send_sms_http(phone, text)
class PhoneSerializer(serializers.Serializer):
    phone = serializers.CharField(required=True)
    hash = serializers.CharField(required=True)

    def validate_phone(self, phone):
        if user_models.Profile.objects.filter(
                is_active=True, phone=phone).exists():
            return phone
        raise serializers.ValidationError(_('profile not found'))

    def validate(self, data):
        if config.DEV_SMS_ON or settings.IS_LOCAL:
            return data

        hash256 = hashlib.sha256()
        hash256.update('{}_{}'.format(
            data['phone'],
            settings.SECRET_SMS_KEY).encode('utf-8'))

        if data['hash'] != hash256.hexdigest():
            raise serializers.ValidationError({'hash': _('wrong hash')})

        return data

    def create(self, validated_data):
        recipient = user_models.Profile.objects.filter(
            is_active=True, phone=validated_data['phone']).first()

        instance = system_models.SmsCode.objects.create(
            sms=common_utils.generator_random(10000, 99999),
            sender=recipient,
            recipient=recipient
        )
        return instance

    class Meta:
        fields = ['phone', 'hash']
        ref_name = 'PhoneSerializer'
        extra_kwargs = {
            'phone': {
                'validators': [validate_international_phonenumber]
            }
        }

Perhaps an example of my code will clarify the situation.
I would keep looking for an error in my code if it always appeared. However, downgrading helps to get rid of the error.

@matthiask
Copy link
Member

matthiask commented Nov 27, 2020

Hmm interesting. Thanks!

I wonder where the behavior change comes from since I cannot find a change in debug_toolbar/panels/request.py which could be responsible for this.

Do you have a way to bisect the djengo-debug-toolbar commit responsible for this behavior?

@folt
Copy link
Contributor Author

folt commented Nov 27, 2020

I can spend some time following
and contribute if I can find the problem

@folt
Copy link
Contributor Author

folt commented Nov 27, 2020

I did some research and this is what I found. This error occurs due to a call to the generate_stats method in the RequestPanel class.

In version 2, the call did not occur due to the code
https://github.com/jazzband/django-debug-toolbar/blob/2.2/debug_toolbar/middleware.py

        # Check for responses where the toolbar can't be inserted.
        content_encoding = response.get("Content-Encoding", "")
        content_type = response.get("Content-Type", "").split(";")[0]
        if any(
            (
                getattr(response, "streaming", False),
                "gzip" in content_encoding,
                content_type not in _HTML_TYPES,
            )
        ):
            return response

In version 3, the order has changed slightly.
https://github.com/jazzband/django-debug-toolbar/blob/3.1.1/debug_toolbar/middleware.py

        # Generate the stats for all requests when the toolbar is being shown,
        # but not necessarily inserted.
        for panel in reversed(toolbar.enabled_panels):
            panel.generate_stats(request, response)
            panel.generate_server_timing(request, response)

        response = self.generate_server_timing_header(response, toolbar.enabled_panels)

        # Check for responses where the toolbar can't be inserted.
        content_encoding = response.get("Content-Encoding", "")
        content_type = response.get("Content-Type", "").split(";")[0]
        if any(
            (
                getattr(response, "streaming", False),
                "gzip" in content_encoding,
                content_type not in _HTML_TYPES,
                request.is_ajax(),
            )
        ):
            # If a AJAX or JSON request, render the toolbar for the history.
            if request.is_ajax() or content_type == "application/json":
                toolbar.render_toolbar()
            return response

I see 2 ways to solve the problem.

  1. prevent this method from being called and return the logic as in version 2.
  2. you need to check and process types in the generate_stats method in the RequestPanel class

I am willing to contribute, but would like to consult with the community for a solution approach.

folt added a commit to folt/django-debug-toolbar that referenced this issue Nov 27, 2020
folt added a commit that referenced this issue Nov 27, 2020
fix AttributeError: 'dict' object has no attribute 'getlist' #1406
folt added a commit that referenced this issue Nov 30, 2020
@folt folt closed this as completed in 1181f2d Dec 1, 2020
@matthiask
Copy link
Member

Thanks!

By the way, if you wanted feedback from the community you should wait a bit before merging your own pull requests. Jazzband of course allows you to do this. But, as always, with power comes responsibility.

(FWIW I think the solution is fine, I would only have had cosmetic suggestions.)

@folt
Copy link
Contributor Author

folt commented Dec 1, 2020

Thanks!

By the way, if you wanted feedback from the community you should wait a bit before merging your own pull requests. Jazzband of course allows you to do this. But, as always, with power comes responsibility.

(FWIW I think the solution is fine, I would only have had cosmetic suggestions.)

I don’t often send contributions anywhere, and not too long ago to Jazzband. Right now this contribution is burning for me because this error breaks my project. But in the future I will not be in such a hurry. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants