prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  min_ip, max_ip fields erroring despite being specified via JSON REST API
  As of commit 4794c4c04fced29b397b58a7689ff725c20ff6bd I'm having a problem where the JSON rest API won't let me create networks - https://22.0.0.2/api/networks/ (docker container instance of Ralph)
  a request sent to 
  ```json
  {
     "name":"test3",
     "address":"2.0.0.0/8",
     "remarks":"",
     "vlan":1,
     "dhcp_broadcast":false,
     "reserved_from_beginning":0,
     "reserved_from_end":0,
     "gateway":null,
     "network_environment":null,
     "kind":null,
     "service_env":null,
     "terminators":[
  
     ],
     "racks":[
  
     ],
     "dns_servers":[
  
     ],
     "min_ip":16777216,
     "max_ip":33554431
  }
  ```
  produces the following result:
  ```json
  {
    "min_ip": [
      "This field is required."
    ],
    "max_ip": [
      "This field is required."
    ]
  }
  ```
  
  This seems to be a known issue with Django REST API, and is possibly a result of min_ip and max_ip being set as non-editable in the model? 
  
  The same request works via the form request mechanism.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `src/ralph/networks/api.py`
  Content:
  ```
  1 # -*- coding: utf-8 -*-
  2 from django.conf import settings
  3 from rest_framework.exceptions import ValidationError
  4 
  5 from ralph.api import RalphAPISerializer, RalphAPIViewSet, router
  6 from ralph.api.serializers import RalphAPISaveSerializer
  7 from ralph.assets.api.serializers import EthernetSerializer
  8 from ralph.networks.models import (
  9     IPAddress,
  10     Network,
  11     NetworkEnvironment,
  12     NetworkKind
  13 )
  14 
  15 
  16 class NetworkEnvironmentSerializer(RalphAPISerializer):
  17     class Meta:
  18         model = NetworkEnvironment
  19         depth = 1
  20 
  21 
  22 class NetworkKindSerializer(RalphAPISerializer):
  23     class Meta:
  24         model = NetworkKind
  25         depth = 1
  26 
  27 
  28 class NetworkSimpleSerializer(RalphAPISerializer):
  29     class Meta:
  30         model = Network
  31         fields = (
  32             'id', 'url', 'name', 'remarks', 'vlan', 'dhcp_broadcast', 'parent',
  33             'network_environment'
  34         )
  35 
  36 
  37 class NetworkSerializer(RalphAPISerializer):
  38     class Meta:
  39         model = Network
  40         depth = 1
  41 
  42 
  43 class IPAddressSerializer(RalphAPISerializer):
  44     network = NetworkSimpleSerializer()
  45     ethernet = EthernetSerializer()
  46 
  47     class Meta:
  48         model = IPAddress
  49         depth = 1
  50         exclude = ('number',)
  51 
  52 
  53 class IPAddressSaveSerializer(RalphAPISaveSerializer):
  54     class Meta:
  55         model = IPAddress
  56 
  57     def validate_dhcp_expose(self, value):
  58         """
  59         Check if dhcp_expose value has changed from True to False.
  60         """
  61         if (
  62             settings.DHCP_ENTRY_FORBID_CHANGE and
  63             self.instance and
  64             self.instance.dhcp_expose and
  65             not value
  66         ):
  67             raise ValidationError(
  68                 'Cannot remove entry from DHCP. Use transition to do this.'
  69             )
  70         return value
  71 
  72 
  73 class IPAddressViewSet(RalphAPIViewSet):
  74     queryset = IPAddress.objects.all()
  75     serializer_class = IPAddressSerializer
  76     save_serializer_class = IPAddressSaveSerializer
  77     prefetch_related = [
  78         'ethernet', 'ethernet__base_object', 'ethernet__base_object__tags',
  79         'network',
  80     ]
  81     filter_fields = [
  82         'hostname', 'ethernet__base_object', 'network', 'network__address',
  83         'status', 'is_public', 'is_management', 'dhcp_expose', 'ethernet__mac',
  84     ]
  85 
  86     def destroy(self, request, *args, **kwargs):
  87         instance = self.get_object()
  88         if instance and instance.dhcp_expose:
  89             raise ValidationError(
  90                 'Could not delete IPAddress when it is exposed in DHCP'
  91             )
  92         return super().destroy(request, *args, **kwargs)
  93 
  94 
  95 class NetworkViewSet(RalphAPIViewSet):
  96     queryset = Network.objects.all()
  97     serializer_class = NetworkSerializer
  98     select_related = ['network_environment', 'kind']
  99     prefetch_related = ['racks']
  100     extended_filter_fields = {
  101         # workaround for custom field for address field defined in admin
  102         'address': ['address'],
  103     }
  104 
  105 
  106 class NetworkEnvironmentViewSet(RalphAPIViewSet):
  107     queryset = NetworkEnvironment.objects.all()
  108     serializer_class = NetworkEnvironmentSerializer
  109 
  110 
  111 class NetworkKindViewSet(RalphAPIViewSet):
  112     queryset = NetworkKind.objects.all()
  113     serializer_class = NetworkKindSerializer
  114 
  115 router.register(r'ipaddresses', IPAddressViewSet)
  116 router.register(r'networks', NetworkViewSet)
  117 router.register(r'network-environments', NetworkEnvironmentViewSet)
  118 router.register(r'network-kinds', NetworkKindViewSet)
  119 urlpatterns = []
  120
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/src/ralph/networks/api.py b/src/ralph/networks/api.py
  --- a/src/ralph/networks/api.py
  +++ b/src/ralph/networks/api.py
  @@ -34,6 +34,13 @@
           )
   
   
  +class NetworkSaveSerializer(RalphAPISerializer):
  +    class Meta:
  +        model = Network
  +        depth = 1
  +        exclude = ('min_ip', 'max_ip')
  +
  +
   class NetworkSerializer(RalphAPISerializer):
       class Meta:
           model = Network
  @@ -95,6 +102,7 @@
   class NetworkViewSet(RalphAPIViewSet):
       queryset = Network.objects.all()
       serializer_class = NetworkSerializer
  +    save_serializer_class = NetworkSaveSerializer
       select_related = ['network_environment', 'kind']
       prefetch_related = ['racks']
       extended_filter_fields = {
  
verification_info: {"golden_diff": "diff --git a/src/ralph/networks/api.py b/src/ralph/networks/api.py\n--- a/src/ralph/networks/api.py\n+++ b/src/ralph/networks/api.py\n@@ -34,6 +34,13 @@\n         )\n \n \n+class NetworkSaveSerializer(RalphAPISerializer):\n+    class Meta:\n+        model = Network\n+        depth = 1\n+        exclude = ('min_ip', 'max_ip')\n+\n+\n class NetworkSerializer(RalphAPISerializer):\n     class Meta:\n         model = Network\n@@ -95,6 +102,7 @@\n class NetworkViewSet(RalphAPIViewSet):\n     queryset = Network.objects.all()\n     serializer_class = NetworkSerializer\n+    save_serializer_class = NetworkSaveSerializer\n     select_related = ['network_environment', 'kind']\n     prefetch_related = ['racks']\n     extended_filter_fields = {\n", "issue": "min_ip, max_ip fields erroring despite being specified via JSON REST API\nAs of commit 4794c4c04fced29b397b58a7689ff725c20ff6bd I'm having a problem where the JSON rest API won't let me create networks - https://22.0.0.2/api/networks/ (docker container instance of Ralph)\r\na request sent to \r\n```json\r\n{\r\n   \"name\":\"test3\",\r\n   \"address\":\"2.0.0.0/8\",\r\n   \"remarks\":\"\",\r\n   \"vlan\":1,\r\n   \"dhcp_broadcast\":false,\r\n   \"reserved_from_beginning\":0,\r\n   \"reserved_from_end\":0,\r\n   \"gateway\":null,\r\n   \"network_environment\":null,\r\n   \"kind\":null,\r\n   \"service_env\":null,\r\n   \"terminators\":[\r\n\r\n   ],\r\n   \"racks\":[\r\n\r\n   ],\r\n   \"dns_servers\":[\r\n\r\n   ],\r\n   \"min_ip\":16777216,\r\n   \"max_ip\":33554431\r\n}\r\n```\r\nproduces the following result:\r\n```json\r\n{\r\n  \"min_ip\": [\r\n    \"This field is required.\"\r\n  ],\r\n  \"max_ip\": [\r\n    \"This field is required.\"\r\n  ]\r\n}\r\n```\r\n\r\nThis seems to be a known issue with Django REST API, and is possibly a result of min_ip and max_ip being set as non-editable in the model? \r\n\r\nThe same request works via the form request mechanism.\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\nfrom django.conf import settings\nfrom rest_framework.exceptions import ValidationError\n\nfrom ralph.api import RalphAPISerializer, RalphAPIViewSet, router\nfrom ralph.api.serializers import RalphAPISaveSerializer\nfrom ralph.assets.api.serializers import EthernetSerializer\nfrom ralph.networks.models import (\n    IPAddress,\n    Network,\n    NetworkEnvironment,\n    NetworkKind\n)\n\n\nclass NetworkEnvironmentSerializer(RalphAPISerializer):\n    class Meta:\n        model = NetworkEnvironment\n        depth = 1\n\n\nclass NetworkKindSerializer(RalphAPISerializer):\n    class Meta:\n        model = NetworkKind\n        depth = 1\n\n\nclass NetworkSimpleSerializer(RalphAPISerializer):\n    class Meta:\n        model = Network\n        fields = (\n            'id', 'url', 'name', 'remarks', 'vlan', 'dhcp_broadcast', 'parent',\n            'network_environment'\n        )\n\n\nclass NetworkSerializer(RalphAPISerializer):\n    class Meta:\n        model = Network\n        depth = 1\n\n\nclass IPAddressSerializer(RalphAPISerializer):\n    network = NetworkSimpleSerializer()\n    ethernet = EthernetSerializer()\n\n    class Meta:\n        model = IPAddress\n        depth = 1\n        exclude = ('number',)\n\n\nclass IPAddressSaveSerializer(RalphAPISaveSerializer):\n    class Meta:\n        model = IPAddress\n\n    def validate_dhcp_expose(self, value):\n        \"\"\"\n        Check if dhcp_expose value has changed from True to False.\n        \"\"\"\n        if (\n            settings.DHCP_ENTRY_FORBID_CHANGE and\n            self.instance and\n            self.instance.dhcp_expose and\n            not value\n        ):\n            raise ValidationError(\n                'Cannot remove entry from DHCP. Use transition to do this.'\n            )\n        return value\n\n\nclass IPAddressViewSet(RalphAPIViewSet):\n    queryset = IPAddress.objects.all()\n    serializer_class = IPAddressSerializer\n    save_serializer_class = IPAddressSaveSerializer\n    prefetch_related = [\n        'ethernet', 'ethernet__base_object', 'ethernet__base_object__tags',\n        'network',\n    ]\n    filter_fields = [\n        'hostname', 'ethernet__base_object', 'network', 'network__address',\n        'status', 'is_public', 'is_management', 'dhcp_expose', 'ethernet__mac',\n    ]\n\n    def destroy(self, request, *args, **kwargs):\n        instance = self.get_object()\n        if instance and instance.dhcp_expose:\n            raise ValidationError(\n                'Could not delete IPAddress when it is exposed in DHCP'\n            )\n        return super().destroy(request, *args, **kwargs)\n\n\nclass NetworkViewSet(RalphAPIViewSet):\n    queryset = Network.objects.all()\n    serializer_class = NetworkSerializer\n    select_related = ['network_environment', 'kind']\n    prefetch_related = ['racks']\n    extended_filter_fields = {\n        # workaround for custom field for address field defined in admin\n        'address': ['address'],\n    }\n\n\nclass NetworkEnvironmentViewSet(RalphAPIViewSet):\n    queryset = NetworkEnvironment.objects.all()\n    serializer_class = NetworkEnvironmentSerializer\n\n\nclass NetworkKindViewSet(RalphAPIViewSet):\n    queryset = NetworkKind.objects.all()\n    serializer_class = NetworkKindSerializer\n\nrouter.register(r'ipaddresses', IPAddressViewSet)\nrouter.register(r'networks', NetworkViewSet)\nrouter.register(r'network-environments', NetworkEnvironmentViewSet)\nrouter.register(r'network-kinds', NetworkKindViewSet)\nurlpatterns = []\n", "path": "src/ralph/networks/api.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\nfrom django.conf import settings\nfrom rest_framework.exceptions import ValidationError\n\nfrom ralph.api import RalphAPISerializer, RalphAPIViewSet, router\nfrom ralph.api.serializers import RalphAPISaveSerializer\nfrom ralph.assets.api.serializers import EthernetSerializer\nfrom ralph.networks.models import (\n    IPAddress,\n    Network,\n    NetworkEnvironment,\n    NetworkKind\n)\n\n\nclass NetworkEnvironmentSerializer(RalphAPISerializer):\n    class Meta:\n        model = NetworkEnvironment\n        depth = 1\n\n\nclass NetworkKindSerializer(RalphAPISerializer):\n    class Meta:\n        model = NetworkKind\n        depth = 1\n\n\nclass NetworkSimpleSerializer(RalphAPISerializer):\n    class Meta:\n        model = Network\n        fields = (\n            'id', 'url', 'name', 'remarks', 'vlan', 'dhcp_broadcast', 'parent',\n            'network_environment'\n        )\n\n\nclass NetworkSaveSerializer(RalphAPISerializer):\n    class Meta:\n        model = Network\n        depth = 1\n        exclude = ('min_ip', 'max_ip')\n\n\nclass NetworkSerializer(RalphAPISerializer):\n    class Meta:\n        model = Network\n        depth = 1\n\n\nclass IPAddressSerializer(RalphAPISerializer):\n    network = NetworkSimpleSerializer()\n    ethernet = EthernetSerializer()\n\n    class Meta:\n        model = IPAddress\n        depth = 1\n        exclude = ('number',)\n\n\nclass IPAddressSaveSerializer(RalphAPISaveSerializer):\n    class Meta:\n        model = IPAddress\n\n    def validate_dhcp_expose(self, value):\n        \"\"\"\n        Check if dhcp_expose value has changed from True to False.\n        \"\"\"\n        if (\n            settings.DHCP_ENTRY_FORBID_CHANGE and\n            self.instance and\n            self.instance.dhcp_expose and\n            not value\n        ):\n            raise ValidationError(\n                'Cannot remove entry from DHCP. Use transition to do this.'\n            )\n        return value\n\n\nclass IPAddressViewSet(RalphAPIViewSet):\n    queryset = IPAddress.objects.all()\n    serializer_class = IPAddressSerializer\n    save_serializer_class = IPAddressSaveSerializer\n    prefetch_related = [\n        'ethernet', 'ethernet__base_object', 'ethernet__base_object__tags',\n        'network',\n    ]\n    filter_fields = [\n        'hostname', 'ethernet__base_object', 'network', 'network__address',\n        'status', 'is_public', 'is_management', 'dhcp_expose', 'ethernet__mac',\n    ]\n\n    def destroy(self, request, *args, **kwargs):\n        instance = self.get_object()\n        if instance and instance.dhcp_expose:\n            raise ValidationError(\n                'Could not delete IPAddress when it is exposed in DHCP'\n            )\n        return super().destroy(request, *args, **kwargs)\n\n\nclass NetworkViewSet(RalphAPIViewSet):\n    queryset = Network.objects.all()\n    serializer_class = NetworkSerializer\n    save_serializer_class = NetworkSaveSerializer\n    select_related = ['network_environment', 'kind']\n    prefetch_related = ['racks']\n    extended_filter_fields = {\n        # workaround for custom field for address field defined in admin\n        'address': ['address'],\n    }\n\n\nclass NetworkEnvironmentViewSet(RalphAPIViewSet):\n    queryset = NetworkEnvironment.objects.all()\n    serializer_class = NetworkEnvironmentSerializer\n\n\nclass NetworkKindViewSet(RalphAPIViewSet):\n    queryset = NetworkKind.objects.all()\n    serializer_class = NetworkKindSerializer\n\nrouter.register(r'ipaddresses', IPAddressViewSet)\nrouter.register(r'networks', NetworkViewSet)\nrouter.register(r'network-environments', NetworkEnvironmentViewSet)\nrouter.register(r'network-kinds', NetworkKindViewSet)\nurlpatterns = []\n", "path": "src/ralph/networks/api.py"}]}