Skip to content
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

Fix KeyError raised when trying to sort application inventory by install count #458

Merged

Conversation

w0de
Copy link
Contributor

@w0de w0de commented Oct 24, 2023

This fixes an exception raised when trying to sort a machine group's application inventory by install count.

Changes:

  • ApplicationListView's install_count column is now an IntegerColumn.
  • The column now has database source, inventoryitem_set__count (get_install_count is still the column's processor).
  • The column is now defined in ApplicationListView.datatable_class instead of the get_datatable monkeypatch.
  • The get_datatable monkeypatch now deletes the column when appropriate. Tested this manually with SHOW_INSTALL_COUNTS = False - the 'Install Count' column is correctly not rendered & nothing in the table seems broken.

To reproduce exception:

  1. Populate at least one device w/ an application inventory in a Sal instance. At least one application should have an install count > 1 (reviewer's mac certainly has multiple Pythons).
  2. Navigate to /inventory/machine/1/ (machine group 1's app inventory).
  3. Attempt to sort by install count. Expected result:
Screen.Recording.2023-10-23.at.6.54.53.PM.mov

Datatables error 7 == server returned a 500. There's only one line in the root traceback:

[24/Oct/2023 01:55:04] ERROR [django.request:224] Internal Server Error: /inventory/machine/1/
Traceback (most recent call last):
  File "/Users/wode/src/sal.w0de/.venv/lib/python3.11/site-packages/django/db/models/options.py", line 575, in get_field
    return self.fields_map[field_name]
           ~~~~~~~~~~~~~~~^^^^^^^^^^^^
KeyError: 'None'

But there's a further useful exception during handling:

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/wode/src/sal.w0de/.venv/lib/python3.11/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/wode/src/sal.w0de/.venv/lib/python3.11/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/wode/src/sal.w0de/.venv/lib/python3.11/site-packages/django/views/generic/base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/wode/src/sal.w0de/.venv/lib/python3.11/site-packages/django/utils/decorators.py", line 43, in _wrapper
    return bound_method(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/wode/src/sal.w0de/.venv/lib/python3.11/site-packages/django/contrib/auth/decorators.py", line 21, in _wrapped_view
    return view_func(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/wode/src/sal.w0de/.venv/lib/python3.11/site-packages/django/utils/decorators.py", line 43, in _wrapper
    return bound_method(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/wode/src/sal.w0de/sal/decorators.py", line 70, in decorator
    return function(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/wode/src/sal.w0de/.venv/lib/python3.11/site-packages/datatableview/views/base.py", line 29, in dispatch
    datatable.configure()
  File "/Users/wode/src/sal.w0de/.venv/lib/python3.11/site-packages/datatableview/datatables.py", line 292, in configure
    self.config = self.normalize_config(self._meta.__dict__, self.query_config)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/wode/src/sal.w0de/.venv/lib/python3.11/site-packages/datatableview/datatables.py", line 338, in normalize_config
    self._ordering_columns = self.ensure_ordering_columns(config["ordering"])
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/wode/src/sal.w0de/.venv/lib/python3.11/site-packages/datatableview/datatables.py", line 427, in ensure_ordering_columns
    field = resolve_orm_path(self.model, name)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/wode/src/sal.w0de/.venv/lib/python3.11/site-packages/datatableview/utils.py", line 64, in resolve_orm_path
    field = endpoint_model._meta.get_field(bits[-1])
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/wode/src/sal.w0de/.venv/lib/python3.11/site-packages/django/db/models/options.py", line 577, in get_field
    raise FieldDoesNotExist("%s has no field named '%s'" % (self.object_name, field_name))
django.core.exceptions.FieldDoesNotExist: Application has no field named 'None'
[24/Oct/2023 01:55:04] ERROR [django.server:157] "GET /inventory/machine/1/?draw=2&columns%5B0%5D%5Bdata%5D=0&columns%5B0%5D%5Bname%5D=name&columns%5B0%5D%5Bsearchable%5D=true&columns%5B0%5D%5Borderable%5D=true&columns%5B0%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B0%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B1%5D%5Bdata%5D=1&columns%5B1%5D%5Bname%5D=bundle-id&columns%5B1%5D%5Bsearchable%5D=true&columns%5B1%5D%5Borderable%5D=true&columns%5B1%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B1%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B2%5D%5Bdata%5D=2&columns%5B2%5D%5Bname%5D=bundle-name&columns%5B2%5D%5Bsearchable%5D=true&columns%5B2%5D%5Borderable%5D=true&columns%5B2%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B2%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B3%5D%5Bdata%5D=3&columns%5B3%5D%5Bname%5D=install-count&columns%5B3%5D%5Bsearchable%5D=true&columns%5B3%5D%5Borderable%5D=true&columns%5B3%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B3%5D%5Bsearch%5D%5Bregex%5D=false&order%5B0%5D%5Bcolumn%5D=3&order%5B0%5D%5Bdir%5D=asc&start=0&length=20&search%5Bvalue%5D=&search%5Bregex%5D=false&_=1698108890069 HTTP/1.1" 500 137349

I believe (not sure) this occurs because the 'install_count' column does not have a defined db source, but is not properly configured as a non-db sourced column. The column is misconfigured due to its idiosyncratic monkeypatch definition.

This causes django-datatable-view to attempt accessing field None on the Application model when asked to sort the column's data.

@grahamgilbert grahamgilbert merged commit dc7f869 into salopensource:main Nov 13, 2023
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants