Repository: nautobot/nautobot

Issue:
1.4.3: Exception during OpenAPI schema generation with nautobot-firewall-models plugin installed
### Environment
* Nautobot version (Docker tag too if applicable): 1.4.3
* Python version: any
* Database platform, version: any
* Middleware(s): n/a
* Plugin(s): `nautobot-firewall-models`

### Steps to Reproduce
1. Install Nautobot 1.4.3, install and enable `nautobot-firewall-models` plugin
2. Start Nautobot server or run `nautobot-server spectacular` command

### Expected Behavior

Server to start up successfully; schema generation to complete without errors.

### Observed Behavior

```
SystemCheckError: System check identified some issues:

ERRORS:
?: (drf_spectacular.E001) Schema generation threw exception "'NoneType' object does not support item assignment"
```

or

```
Traceback (most recent call last):
  File "/usr/local/bin/nautobot-server", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.7/site-packages/nautobot/core/cli.py", line 61, in main
    initializer=_configure_settings,  # Called after defaults
  File "/usr/local/lib/python3.7/site-packages/nautobot/core/runner/runner.py", line 263, in run_app
    management.execute_from_command_line([runner_name, command] + command_args)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 413, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 354, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 398, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python3.7/site-packages/drf_spectacular/management/commands/spectacular.py", line 58, in handle
    schema = generator.get_schema(request=None, public=True)
  File "/usr/local/lib/python3.7/site-packages/drf_spectacular/generators.py", line 268, in get_schema
    paths=self.parse(request, public),
  File "/usr/local/lib/python3.7/site-packages/drf_spectacular/generators.py", line 240, in parse
    path, path_regex, path_prefix, method, self.registry
  File "/usr/local/lib/python3.7/site-packages/nautobot/core/api/schema.py", line 63, in get_operation
    operation = super().get_operation(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/drf_spectacular/openapi.py", line 82, in get_operation
    request_body = self._get_request_body()
  File "/usr/local/lib/python3.7/site-packages/drf_spectacular/openapi.py", line 1198, in _get_request_body
    schema, request_body_required = self._get_request_for_media_type(request_serializer, direction)
  File "/usr/local/lib/python3.7/site-packages/drf_spectacular/openapi.py", line 1220, in _get_request_for_media_type
    schema = self._unwrap_list_serializer(serializer, direction)
  File "/usr/local/lib/python3.7/site-packages/drf_spectacular/openapi.py", line 1301, in _unwrap_list_serializer
    result = self._unwrap_list_serializer(serializer.child, direction)
  File "/usr/local/lib/python3.7/site-packages/drf_spectacular/openapi.py", line 1298, in _unwrap_list_serializer
    component = self.resolve_serializer(serializer, direction)
  File "/usr/local/lib/python3.7/site-packages/nautobot/core/api/schema.py", line 244, in resolve_serializer
    component = super().resolve_serializer(serializer, direction, bypass_extensions)
  File "/usr/local/lib/python3.7/site-packages/drf_spectacular/openapi.py", line 1496, in resolve_serializer
    component.schema = self._map_serializer(serializer, direction, bypass_extensions)
  File "/usr/local/lib/python3.7/site-packages/drf_spectacular/openapi.py", line 882, in _map_serializer
    schema = self._map_basic_serializer(serializer, direction)
  File "/usr/local/lib/python3.7/site-packages/drf_spectacular/openapi.py", line 969, in _map_basic_serializer
    schema = self._map_serializer_field(field, direction)
  File "/usr/local/lib/python3.7/site-packages/drf_spectacular/openapi.py", line 649, in _map_serializer_field
    component = self.resolve_serializer(field, direction)
  File "/usr/local/lib/python3.7/site-packages/nautobot/core/api/schema.py", line 246, in resolve_serializer
    component.schema["required"] = ["id"]
TypeError: 'NoneType' object does not support item assignment
```

No error is seen with Nautobot 1.4.2 or earlier or without installing `nautobot-firewall-models`. Appears to be a bug introduced by #2398.


Discussion:

Resolving patch:
diff --git a/nautobot/core/api/schema.py b/nautobot/core/api/schema.py
--- a/nautobot/core/api/schema.py
+++ b/nautobot/core/api/schema.py
@@ -242,7 +242,13 @@ def resolve_serializer(self, serializer, direction, bypass_extensions=False):
         but Nautobot bulk partial updates require the `id` field to be specified for each object to update.
         """
         component = super().resolve_serializer(serializer, direction, bypass_extensions)
-        if self.is_bulk_action and self.is_partial_action and direction == "request":
+        if (
+            component
+            and component.schema is not None
+            and self.is_bulk_action
+            and self.is_partial_action
+            and direction == "request"
+        ):
             component.schema["required"] = ["id"]
         return component
 


Test patch: