Repository: netbox-community/netbox

Issue:
Exception via malformed API request to /available-ips/
### NetBox version

v3.6.6

### Python version

3.8

### Steps to Reproduce

1. Get the ID of a prefix (in this case I'm using prefix 32)
2. Use curl to make a POST API request with empty body but default `Content-Type: application/x-www-form-urlencoded` 

```
curl -d '' -vsS -H "Authorization: Token $TOKEN" "$NETBOX/api/ipam/prefixes/32/available-ips/"
```

### Expected Behavior

Request is either accepted (since the body of the request isn't used), or is validated and rejected with a well-formed 4xx response from the API

### Observed Behavior

An exception is raised:

```
< HTTP/1.1 500 Internal Server Error
...
                            <p>
                                There was a problem with your request. Please contact an administrator.
                            </p>

                        <hr />
                        <p>
                            The complete exception is provided below:
                        </p>
<pre class="block"><strong>&lt;class &#x27;AttributeError&#x27;&gt;</strong><br />
This QueryDict instance is immutable
```

The backtrace is mailed out to ADMINS if this has been set up.

```
Traceback (most recent call last):
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view
    return view_func(*args, **kwargs)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/views/generic/base.py", line 104, in view
    return self.dispatch(request, *args, **kwargs)
  File "/opt/netbox/venv/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/opt/netbox/venv/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/opt/netbox/venv/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/opt/netbox/venv/lib/python3.8/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/opt/netbox/netbox/ipam/api/views.py", line 451, in post
    return super().post(request, pk)
  File "/opt/netbox/netbox/ipam/api/views.py", line 293, in post
    requested_objects = self.prep_object_data(requested_objects, available_objects, parent)
  File "/opt/netbox/netbox/ipam/api/views.py", line 434, in prep_object_data
    request_data.update({
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/utils/datastructures.py", line 211, in update
    self.setlistdefault(key).append(value)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/http/request.py", line 584, in setlistdefault
    self._assert_mutable()
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/http/request.py", line 552, in _assert_mutable
    raise AttributeError("This QueryDict instance is immutable")

Exception Type: AttributeError at /api/ipam/prefixes/32/available-ips/
Exception Value: This QueryDict instance is immutable
Raised during: ipam.api.views.PrefixAvailableIPAddressesView
Request information:
USER: admin
```



Discussion:

Resolving patch:
diff --git a/netbox/ipam/api/views.py b/netbox/ipam/api/views.py
--- a/netbox/ipam/api/views.py
+++ b/netbox/ipam/api/views.py
@@ -1,3 +1,5 @@
+from copy import deepcopy
+
 from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
 from django.db import transaction
 from django.shortcuts import get_object_or_404
@@ -290,7 +292,7 @@ def post(self, request, pk):
                 )
 
             # Prepare object data for deserialization
-            requested_objects = self.prep_object_data(requested_objects, available_objects, parent)
+            requested_objects = self.prep_object_data(deepcopy(requested_objects), available_objects, parent)
 
             # Initialize the serializer with a list or a single object depending on what was requested
             serializer_class = get_serializer_for_model(self.queryset.model)


Test patch: