We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
KeyError thrown and Incorrect display_options present when altering a column type from TEXT to DATE
## Description
When patching a column from `TEXT` to `DATE`,
* Irrelevant `display_option "show_as_percentage"` is present on the column
* Further requests to `columns/` and `tables/` endpoints, throws a 500 with keyError.

## Reproduction
* Create a TEXT column
* PATCH it to DATE. (Alternatively, change type to DATE on the frontend).
   ```
  {
    type: "DATE",
    display_options: {},
    type_options: {},
  }
   ```
* Notice that the table fails to loads on the frontend.
* Requests to `columns/` and `tables/` endpoints result in a 500 with,
   > Got KeyError when attempting to get a value for field `format` on serializer `TimeFormatDisplayOptionSerializer`.\nThe serializer field might be named incorrectly and not match any attribute or key on the `dict` instance.\nOriginal exception text was: 'format'.
* Check the preloaded tables list by executing the following on the developer tools:
  ```javascript
  JSON.parse(document.querySelector('#common-data').textContent).tables
  ```
* Notice that incorrect fields are present in the display_options of the modified column: 
   ```javascript
  {
    id: 34,
    name: "Date Shared",
    type: "DATE",
    type_options :null,
    display_options:{
      show_as_percentage: false
    }
  }
   ```

## Expected behavior
* `display_options` field should not contain invalid entries.
* The 500 with keyError should not be thrown.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mathesar/api/exceptions/mixins.py`
Content:
```
1 from rest_framework.serializers import Serializer
2 from rest_framework.utils.serializer_helpers import ReturnList
3 from rest_framework_friendly_errors.mixins import FriendlyErrorMessagesMixin
4 from django.core.exceptions import ValidationError as DjangoValidationError
5 from rest_framework.exceptions import ValidationError as RestValidationError
6 from mathesar.api.exceptions.generic_exceptions.base_exceptions import ErrorBody
7 
8 
9 class MathesarErrorMessageMixin(FriendlyErrorMessagesMixin):
10     def is_pretty(self, error):
11         return isinstance(error, dict) and tuple(error.keys()) == ErrorBody._fields
12 
13     def build_pretty_errors(self, errors, serializer=None):
14 
15         """
16         This method build on top of `build_pretty_errors` method of the superclass
17         It provides the following additional features
18         1. Avoids processing prettified exceptions
19         2. Add field to the pretty exception body if raised by field validation method
20         """
21         pretty = []
22         for error_type in errors:
23             error = errors[error_type]
24             if error_type == 'non_field_errors':
25                 if self.is_pretty(error):
26                     pretty.append(error)
27                 else:
28                     pretty.extend(self.get_non_field_error_entries(errors[error_type]))
29             else:
30                 field = self.fields.fields[error_type]
31                 if isinstance(field, Serializer) and type(errors[error_type]) == dict:
32                     field.initial_data = self.initial_data[error_type]
33                     child_errors = field.build_pretty_errors(errors[error_type])
34                     pretty += child_errors
35                     continue
36                 if self.is_pretty(error):
37                     if 'field' not in error or error['field'] is None or str(error['field']) == 'None':
38                         error['field'] = error_type
39                     pretty.append(error)
40                 else:
41                     pretty.extend(self.get_field_error_entries(errors[error_type], field))
42         if pretty:
43             return pretty
44         return []
45 
46     def _run_validator(self, validator, field, message):
47         """
48         This method build on top of `_run_validator` method of the superclass
49         It provides the following additional features
50         1. Includes serializer if `required_context` is True similar to the behaviour of drf
51         """
52         try:
53             args = []
54             if getattr(validator, 'requires_context', False):
55                 args.append(field)
56             validator(self.initial_data[field.field_name], *args)
57         except (DjangoValidationError, RestValidationError) as err:
58             err_message = err.detail[0] if hasattr(err, 'detail') else err.message
59             return err_message == message
60 
61     @property
62     def errors(self):
63         """
64         This method build on top of `errors` property of the superclass to return a list instead of a dictionary
65         """
66         ugly_errors = super(FriendlyErrorMessagesMixin, self).errors
67         pretty_errors = self.build_pretty_errors(ugly_errors)
68         return ReturnList(pretty_errors, serializer=self)
69 
70     @property
71     def field_map(self):
72         """
73         This method build on top of `field_map` property of the superclass
74         It provides the following additional features
75         1. Adds `ListSerializer` to `relation` field list
76         """
77         parent_field_map = super(FriendlyErrorMessagesMixin, self).field_map
78         # Add missing `ListSerializer to existing relation list`
79         parent_field_map['relation'].append('ListSerializer')
80         return parent_field_map
81 
82     def get_field_kwargs(self, field, field_data):
83         """
84         This method build on top of `get_field_kwargs` method of the superclass
85         It provides the following fixes
86         1. Fixes file type length value to use name of the file instead of the size of the file,
87          matching the default behaviour of drf
88         """
89         field_type = field.__class__.__name__
90         kwargs = {
91             'data_type': type(field_data).__name__
92         }
93         if field_type in self.field_map['boolean']:
94             kwargs.update({'input': field_data})
95         elif field_type in self.field_map['string']:
96             kwargs.update(
97                 {
98                     'max_length': getattr(field, 'max_length', None),
99                     'min_length': getattr(field, 'min_length', None),
100                     'value': field_data
101                 }
102             )
103         elif field_type in self.field_map['numeric']:
104 
105             kwargs.update(
106                 {
107                     'min_value': field.min_value,
108                     'max_value': field.max_value,
109                     'decimal_places': getattr(field, 'decimal_places', None),
110                     'max_decimal_places': getattr(field, 'decimal_places', None),
111                     'max_digits': getattr(field, 'max_digits', None)
112                 }
113             )
114             max_digits = kwargs['max_digits']
115             decimal_places = kwargs['decimal_places']
116             if max_digits is not None and decimal_places is not None:
117                 whole_digits = max_digits - decimal_places
118                 kwargs.update({'max_whole_digits': whole_digits})
119         elif field_type in self.field_map['date'].keys():
120             kwargs.update({'format': self.field_map['date'][field_type]})
121         elif field_type in self.field_map['choice']:
122             kwargs.update(
123                 {
124                     'input': field_data,
125                     'input_type': type(field_data).__name__
126                 }
127             )
128         elif field_type in self.field_map['file']:
129             kwargs.update(
130                 {
131                     'max_length': field.max_length,
132                     # Parent method calculates the length of the file instead of the filename,
133                     # we are changing it to calculate length of the file name
134                     'length': len(field.parent.data.get(field.source, '').name)
135                 }
136             )
137         elif field_type in self.field_map['composite']:
138             kwargs.update(
139                 {
140                     'input_type': type(field_data).__name__,
141                     'max_length': getattr(field, 'max_length', None),
142                     'min_length': getattr(field, 'min_length', None)
143                 }
144             )
145         elif field_type in self.field_map['relation']:
146             kwargs.update(
147                 {
148                     'pk_value': field_data,
149                     'data_type': type(field_data).__name__,
150                     'input_type': type(field_data).__name__,
151                     'slug_name': getattr(field, 'slug_field', None),
152                     'value': field_data
153                 }
154             )
155         else:
156             kwargs.update({'max_length': getattr(field, 'max_length', None)})
157         return kwargs
158
```

Path: `mathesar/api/serializers/shared_serializers.py`
Content:
```
1 from django.core.exceptions import ImproperlyConfigured
2 from rest_framework import serializers
3 
4 from mathesar.api.exceptions.mixins import MathesarErrorMessageMixin
5 from mathesar.database.types import MathesarTypeIdentifier, get_mathesar_type_from_db_type
6 
7 
8 class ReadOnlyPolymorphicSerializerMappingMixin:
9     """
10     This serializer mixin is helpful in serializing polymorphic models,
11     by switching to correct serializer based on the mapping field value.
12     """
13 
14     def __new__(cls, *args, **kwargs):
15         if cls.serializers_mapping is None:
16             raise ImproperlyConfigured(
17                 '`{cls}` is missing a '
18                 '`{cls}.model_serializer_mapping` attribute'.format(cls=cls.__name__)
19             )
20         return super().__new__(cls, *args, **kwargs)
21 
22     def __init__(self, *args, **kwargs):
23         super().__init__(*args, **kwargs)
24         self.serializers_cls_mapping = {}
25         serializers_mapping = self.serializers_mapping
26         self.serializers_mapping = {}
27         for identifier, serializer_cls in serializers_mapping.items():
28             if callable(serializer_cls):
29                 serializer = serializer_cls(*args, **kwargs)
30                 serializer.parent = self
31             else:
32                 serializer = serializer_cls
33             self.serializers_mapping[identifier] = serializer
34             self.serializers_cls_mapping[identifier] = serializer_cls
35 
36     def to_representation(self, instance):
37         serializer = self.serializers_mapping.get(self.get_mapping_field(), None)
38         if serializer is not None:
39             self.__class__ = self.serializers_cls_mapping.get(self.get_mapping_field())
40             return serializer.to_representation(instance)
41         else:
42             raise Exception(f"Cannot find a matching serializer for the specified type {self.get_mapping_field()}")
43 
44     def get_mapping_field(self):
45         mapping_field = getattr(self, "mapping_field", None)
46         if mapping_field is None:
47             raise Exception(
48                 "Add a `mapping_field` to be used as a identifier"
49                 "or override this method to return a identifier to identify a proper serializer"
50             )
51         return mapping_field
52 
53 
54 class ReadWritePolymorphicSerializerMappingMixin(ReadOnlyPolymorphicSerializerMappingMixin):
55     def to_internal_value(self, data):
56         serializer = self.serializers_mapping.get(self.get_mapping_field())
57         if serializer is not None:
58             self.__class__ = self.serializers_cls_mapping.get(self.get_mapping_field())
59             return serializer.to_internal_value(data=data)
60         else:
61             raise Exception(f"Cannot find a matching serializer for the specified type {self.get_mapping_field()}")
62 
63 
64 class MonkeyPatchPartial:
65     """
66     Work around bug #3847 in djangorestframework by monkey-patching the partial
67     attribute of the root serializer during the call to validate_empty_values.
68     https://github.com/encode/django-rest-framework/issues/3847
69     """
70 
71     def __init__(self, root):
72         self._root = root
73 
74     def __enter__(self):
75         self._old = getattr(self._root, 'partial')
76         setattr(self._root, 'partial', False)
77 
78     def __exit__(self, *args):
79         setattr(self._root, 'partial', self._old)
80 
81 
82 class OverrideRootPartialMixin:
83     """
84     This mixin is used to convert a serializer into a partial serializer,
85     based on the serializer `partial` property rather than the parent's `partial` property.
86     Refer to the issue
87         https://github.com/encode/django-rest-framework/issues/3847
88     """
89 
90     def run_validation(self, *args, **kwargs):
91         if not self.partial:
92             with MonkeyPatchPartial(self.root):
93                 return super().run_validation(*args, **kwargs)
94         return super().run_validation(*args, **kwargs)
95 
96 
97 class CustomBooleanLabelSerializer(MathesarErrorMessageMixin, serializers.Serializer):
98     TRUE = serializers.CharField()
99     FALSE = serializers.CharField()
100 
101 
102 DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY = 'db_type'
103 
104 
105 class BooleanDisplayOptionSerializer(MathesarErrorMessageMixin, OverrideRootPartialMixin, serializers.Serializer):
106     input = serializers.ChoiceField(choices=[("dropdown", "dropdown"), ("checkbox", "checkbox")])
107     custom_labels = CustomBooleanLabelSerializer(required=False)
108 
109 
110 class AbstractNumberDisplayOptionSerializer(serializers.Serializer):
111     number_format = serializers.ChoiceField(allow_null=True, required=False, choices=['english', 'german', 'french', 'hindi', 'swiss'])
112 
113 
114 class NumberDisplayOptionSerializer(
115     MathesarErrorMessageMixin,
116     OverrideRootPartialMixin,
117     AbstractNumberDisplayOptionSerializer
118 ):
119     show_as_percentage = serializers.BooleanField(default=False)
120 
121 
122 class TimeFormatDisplayOptionSerializer(
123     MathesarErrorMessageMixin,
124     OverrideRootPartialMixin,
125     serializers.Serializer
126 ):
127     format = serializers.CharField(max_length=255)
128 
129 
130 class DurationDisplayOptionSerializer(MathesarErrorMessageMixin, OverrideRootPartialMixin, serializers.Serializer):
131     min = serializers.CharField(max_length=255)
132     max = serializers.CharField(max_length=255)
133     show_units = serializers.BooleanField()
134 
135 
136 class DisplayOptionsMappingSerializer(
137     MathesarErrorMessageMixin,
138     OverrideRootPartialMixin,
139     ReadWritePolymorphicSerializerMappingMixin,
140     serializers.Serializer
141 ):
142     serializers_mapping = {
143         MathesarTypeIdentifier.BOOLEAN.value: BooleanDisplayOptionSerializer,
144         MathesarTypeIdentifier.NUMBER.value: NumberDisplayOptionSerializer,
145         MathesarTypeIdentifier.DATETIME.value: TimeFormatDisplayOptionSerializer,
146         MathesarTypeIdentifier.DATE.value: TimeFormatDisplayOptionSerializer,
147         MathesarTypeIdentifier.TIME.value: TimeFormatDisplayOptionSerializer,
148         MathesarTypeIdentifier.DURATION.value: DurationDisplayOptionSerializer,
149     }
150 
151     def get_mapping_field(self):
152         db_type = self.context[DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY]
153         mathesar_type = get_mathesar_type_from_db_type(db_type)
154         return mathesar_type
155
```
--- 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()

```

diff --git a/mathesar/api/exceptions/mixins.py b/mathesar/api/exceptions/mixins.py
--- a/mathesar/api/exceptions/mixins.py
+++ b/mathesar/api/exceptions/mixins.py
@@ -27,7 +27,7 @@
                 else:
                     pretty.extend(self.get_non_field_error_entries(errors[error_type]))
             else:
-                field = self.fields.fields[error_type]
+                field = self.get_serializer_fields().fields[error_type]
                 if isinstance(field, Serializer) and type(errors[error_type]) == dict:
                     field.initial_data = self.initial_data[error_type]
                     child_errors = field.build_pretty_errors(errors[error_type])
@@ -43,6 +43,9 @@
             return pretty
         return []
 
+    def get_serializer_fields(self):
+        return self.fields
+
     def _run_validator(self, validator, field, message):
         """
         This method build on top of `_run_validator` method of the superclass
diff --git a/mathesar/api/serializers/shared_serializers.py b/mathesar/api/serializers/shared_serializers.py
--- a/mathesar/api/serializers/shared_serializers.py
+++ b/mathesar/api/serializers/shared_serializers.py
@@ -36,7 +36,6 @@
     def to_representation(self, instance):
         serializer = self.serializers_mapping.get(self.get_mapping_field(), None)
         if serializer is not None:
-            self.__class__ = self.serializers_cls_mapping.get(self.get_mapping_field())
             return serializer.to_representation(instance)
         else:
             raise Exception(f"Cannot find a matching serializer for the specified type {self.get_mapping_field()}")
@@ -55,7 +54,6 @@
     def to_internal_value(self, data):
         serializer = self.serializers_mapping.get(self.get_mapping_field())
         if serializer is not None:
-            self.__class__ = self.serializers_cls_mapping.get(self.get_mapping_field())
             return serializer.to_internal_value(data=data)
         else:
             raise Exception(f"Cannot find a matching serializer for the specified type {self.get_mapping_field()}")
@@ -94,6 +92,11 @@
         return super().run_validation(*args, **kwargs)
 
 
+class MathesarPolymorphicErrorMixin(MathesarErrorMessageMixin):
+    def get_serializer_fields(self):
+        return self.serializers_mapping[self.get_mapping_field()].fields
+
+
 class CustomBooleanLabelSerializer(MathesarErrorMessageMixin, serializers.Serializer):
     TRUE = serializers.CharField()
     FALSE = serializers.CharField()
@@ -134,8 +137,8 @@
 
 
 class DisplayOptionsMappingSerializer(
-    MathesarErrorMessageMixin,
     OverrideRootPartialMixin,
+    MathesarPolymorphicErrorMixin,
     ReadWritePolymorphicSerializerMappingMixin,
     serializers.Serializer
 ):

{"golden_diff": "diff --git a/mathesar/api/exceptions/mixins.py b/mathesar/api/exceptions/mixins.py\n--- a/mathesar/api/exceptions/mixins.py\n+++ b/mathesar/api/exceptions/mixins.py\n@@ -27,7 +27,7 @@\n                 else:\n                     pretty.extend(self.get_non_field_error_entries(errors[error_type]))\n             else:\n-                field = self.fields.fields[error_type]\n+                field = self.get_serializer_fields().fields[error_type]\n                 if isinstance(field, Serializer) and type(errors[error_type]) == dict:\n                     field.initial_data = self.initial_data[error_type]\n                     child_errors = field.build_pretty_errors(errors[error_type])\n@@ -43,6 +43,9 @@\n             return pretty\n         return []\n \n+    def get_serializer_fields(self):\n+        return self.fields\n+\n     def _run_validator(self, validator, field, message):\n         \"\"\"\n         This method build on top of `_run_validator` method of the superclass\ndiff --git a/mathesar/api/serializers/shared_serializers.py b/mathesar/api/serializers/shared_serializers.py\n--- a/mathesar/api/serializers/shared_serializers.py\n+++ b/mathesar/api/serializers/shared_serializers.py\n@@ -36,7 +36,6 @@\n     def to_representation(self, instance):\n         serializer = self.serializers_mapping.get(self.get_mapping_field(), None)\n         if serializer is not None:\n-            self.__class__ = self.serializers_cls_mapping.get(self.get_mapping_field())\n             return serializer.to_representation(instance)\n         else:\n             raise Exception(f\"Cannot find a matching serializer for the specified type {self.get_mapping_field()}\")\n@@ -55,7 +54,6 @@\n     def to_internal_value(self, data):\n         serializer = self.serializers_mapping.get(self.get_mapping_field())\n         if serializer is not None:\n-            self.__class__ = self.serializers_cls_mapping.get(self.get_mapping_field())\n             return serializer.to_internal_value(data=data)\n         else:\n             raise Exception(f\"Cannot find a matching serializer for the specified type {self.get_mapping_field()}\")\n@@ -94,6 +92,11 @@\n         return super().run_validation(*args, **kwargs)\n \n \n+class MathesarPolymorphicErrorMixin(MathesarErrorMessageMixin):\n+    def get_serializer_fields(self):\n+        return self.serializers_mapping[self.get_mapping_field()].fields\n+\n+\n class CustomBooleanLabelSerializer(MathesarErrorMessageMixin, serializers.Serializer):\n     TRUE = serializers.CharField()\n     FALSE = serializers.CharField()\n@@ -134,8 +137,8 @@\n \n \n class DisplayOptionsMappingSerializer(\n-    MathesarErrorMessageMixin,\n     OverrideRootPartialMixin,\n+    MathesarPolymorphicErrorMixin,\n     ReadWritePolymorphicSerializerMappingMixin,\n     serializers.Serializer\n ):\n", "issue": "KeyError thrown and Incorrect display_options present when altering a column type from TEXT to DATE\n## Description\r\nWhen patching a column from `TEXT` to `DATE`,\r\n* Irrelevant `display_option \"show_as_percentage\"` is present on the column\r\n* Further requests to `columns/` and `tables/` endpoints, throws a 500 with keyError.\r\n\r\n## Reproduction\r\n* Create a TEXT column\r\n* PATCH it to DATE. (Alternatively, change type to DATE on the frontend).\r\n   ```\r\n  {\r\n    type: \"DATE\",\r\n    display_options: {},\r\n    type_options: {},\r\n  }\r\n   ```\r\n* Notice that the table fails to loads on the frontend.\r\n* Requests to `columns/` and `tables/` endpoints result in a 500 with,\r\n   > Got KeyError when attempting to get a value for field `format` on serializer `TimeFormatDisplayOptionSerializer`.\\nThe serializer field might be named incorrectly and not match any attribute or key on the `dict` instance.\\nOriginal exception text was: 'format'.\r\n* Check the preloaded tables list by executing the following on the developer tools:\r\n  ```javascript\r\n  JSON.parse(document.querySelector('#common-data').textContent).tables\r\n  ```\r\n* Notice that incorrect fields are present in the display_options of the modified column: \r\n   ```javascript\r\n  {\r\n    id: 34,\r\n    name: \"Date Shared\",\r\n    type: \"DATE\",\r\n    type_options :null,\r\n    display_options:{\r\n      show_as_percentage: false\r\n    }\r\n  }\r\n   ```\r\n\r\n## Expected behavior\r\n* `display_options` field should not contain invalid entries.\r\n* The 500 with keyError should not be thrown.\n", "before_files": [{"content": "from rest_framework.serializers import Serializer\nfrom rest_framework.utils.serializer_helpers import ReturnList\nfrom rest_framework_friendly_errors.mixins import FriendlyErrorMessagesMixin\nfrom django.core.exceptions import ValidationError as DjangoValidationError\nfrom rest_framework.exceptions import ValidationError as RestValidationError\nfrom mathesar.api.exceptions.generic_exceptions.base_exceptions import ErrorBody\n\n\nclass MathesarErrorMessageMixin(FriendlyErrorMessagesMixin):\n    def is_pretty(self, error):\n        return isinstance(error, dict) and tuple(error.keys()) == ErrorBody._fields\n\n    def build_pretty_errors(self, errors, serializer=None):\n\n        \"\"\"\n        This method build on top of `build_pretty_errors` method of the superclass\n        It provides the following additional features\n        1. Avoids processing prettified exceptions\n        2. Add field to the pretty exception body if raised by field validation method\n        \"\"\"\n        pretty = []\n        for error_type in errors:\n            error = errors[error_type]\n            if error_type == 'non_field_errors':\n                if self.is_pretty(error):\n                    pretty.append(error)\n                else:\n                    pretty.extend(self.get_non_field_error_entries(errors[error_type]))\n            else:\n                field = self.fields.fields[error_type]\n                if isinstance(field, Serializer) and type(errors[error_type]) == dict:\n                    field.initial_data = self.initial_data[error_type]\n                    child_errors = field.build_pretty_errors(errors[error_type])\n                    pretty += child_errors\n                    continue\n                if self.is_pretty(error):\n                    if 'field' not in error or error['field'] is None or str(error['field']) == 'None':\n                        error['field'] = error_type\n                    pretty.append(error)\n                else:\n                    pretty.extend(self.get_field_error_entries(errors[error_type], field))\n        if pretty:\n            return pretty\n        return []\n\n    def _run_validator(self, validator, field, message):\n        \"\"\"\n        This method build on top of `_run_validator` method of the superclass\n        It provides the following additional features\n        1. Includes serializer if `required_context` is True similar to the behaviour of drf\n        \"\"\"\n        try:\n            args = []\n            if getattr(validator, 'requires_context', False):\n                args.append(field)\n            validator(self.initial_data[field.field_name], *args)\n        except (DjangoValidationError, RestValidationError) as err:\n            err_message = err.detail[0] if hasattr(err, 'detail') else err.message\n            return err_message == message\n\n    @property\n    def errors(self):\n        \"\"\"\n        This method build on top of `errors` property of the superclass to return a list instead of a dictionary\n        \"\"\"\n        ugly_errors = super(FriendlyErrorMessagesMixin, self).errors\n        pretty_errors = self.build_pretty_errors(ugly_errors)\n        return ReturnList(pretty_errors, serializer=self)\n\n    @property\n    def field_map(self):\n        \"\"\"\n        This method build on top of `field_map` property of the superclass\n        It provides the following additional features\n        1. Adds `ListSerializer` to `relation` field list\n        \"\"\"\n        parent_field_map = super(FriendlyErrorMessagesMixin, self).field_map\n        # Add missing `ListSerializer to existing relation list`\n        parent_field_map['relation'].append('ListSerializer')\n        return parent_field_map\n\n    def get_field_kwargs(self, field, field_data):\n        \"\"\"\n        This method build on top of `get_field_kwargs` method of the superclass\n        It provides the following fixes\n        1. Fixes file type length value to use name of the file instead of the size of the file,\n         matching the default behaviour of drf\n        \"\"\"\n        field_type = field.__class__.__name__\n        kwargs = {\n            'data_type': type(field_data).__name__\n        }\n        if field_type in self.field_map['boolean']:\n            kwargs.update({'input': field_data})\n        elif field_type in self.field_map['string']:\n            kwargs.update(\n                {\n                    'max_length': getattr(field, 'max_length', None),\n                    'min_length': getattr(field, 'min_length', None),\n                    'value': field_data\n                }\n            )\n        elif field_type in self.field_map['numeric']:\n\n            kwargs.update(\n                {\n                    'min_value': field.min_value,\n                    'max_value': field.max_value,\n                    'decimal_places': getattr(field, 'decimal_places', None),\n                    'max_decimal_places': getattr(field, 'decimal_places', None),\n                    'max_digits': getattr(field, 'max_digits', None)\n                }\n            )\n            max_digits = kwargs['max_digits']\n            decimal_places = kwargs['decimal_places']\n            if max_digits is not None and decimal_places is not None:\n                whole_digits = max_digits - decimal_places\n                kwargs.update({'max_whole_digits': whole_digits})\n        elif field_type in self.field_map['date'].keys():\n            kwargs.update({'format': self.field_map['date'][field_type]})\n        elif field_type in self.field_map['choice']:\n            kwargs.update(\n                {\n                    'input': field_data,\n                    'input_type': type(field_data).__name__\n                }\n            )\n        elif field_type in self.field_map['file']:\n            kwargs.update(\n                {\n                    'max_length': field.max_length,\n                    # Parent method calculates the length of the file instead of the filename,\n                    # we are changing it to calculate length of the file name\n                    'length': len(field.parent.data.get(field.source, '').name)\n                }\n            )\n        elif field_type in self.field_map['composite']:\n            kwargs.update(\n                {\n                    'input_type': type(field_data).__name__,\n                    'max_length': getattr(field, 'max_length', None),\n                    'min_length': getattr(field, 'min_length', None)\n                }\n            )\n        elif field_type in self.field_map['relation']:\n            kwargs.update(\n                {\n                    'pk_value': field_data,\n                    'data_type': type(field_data).__name__,\n                    'input_type': type(field_data).__name__,\n                    'slug_name': getattr(field, 'slug_field', None),\n                    'value': field_data\n                }\n            )\n        else:\n            kwargs.update({'max_length': getattr(field, 'max_length', None)})\n        return kwargs\n", "path": "mathesar/api/exceptions/mixins.py"}, {"content": "from django.core.exceptions import ImproperlyConfigured\nfrom rest_framework import serializers\n\nfrom mathesar.api.exceptions.mixins import MathesarErrorMessageMixin\nfrom mathesar.database.types import MathesarTypeIdentifier, get_mathesar_type_from_db_type\n\n\nclass ReadOnlyPolymorphicSerializerMappingMixin:\n    \"\"\"\n    This serializer mixin is helpful in serializing polymorphic models,\n    by switching to correct serializer based on the mapping field value.\n    \"\"\"\n\n    def __new__(cls, *args, **kwargs):\n        if cls.serializers_mapping is None:\n            raise ImproperlyConfigured(\n                '`{cls}` is missing a '\n                '`{cls}.model_serializer_mapping` attribute'.format(cls=cls.__name__)\n            )\n        return super().__new__(cls, *args, **kwargs)\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.serializers_cls_mapping = {}\n        serializers_mapping = self.serializers_mapping\n        self.serializers_mapping = {}\n        for identifier, serializer_cls in serializers_mapping.items():\n            if callable(serializer_cls):\n                serializer = serializer_cls(*args, **kwargs)\n                serializer.parent = self\n            else:\n                serializer = serializer_cls\n            self.serializers_mapping[identifier] = serializer\n            self.serializers_cls_mapping[identifier] = serializer_cls\n\n    def to_representation(self, instance):\n        serializer = self.serializers_mapping.get(self.get_mapping_field(), None)\n        if serializer is not None:\n            self.__class__ = self.serializers_cls_mapping.get(self.get_mapping_field())\n            return serializer.to_representation(instance)\n        else:\n            raise Exception(f\"Cannot find a matching serializer for the specified type {self.get_mapping_field()}\")\n\n    def get_mapping_field(self):\n        mapping_field = getattr(self, \"mapping_field\", None)\n        if mapping_field is None:\n            raise Exception(\n                \"Add a `mapping_field` to be used as a identifier\"\n                \"or override this method to return a identifier to identify a proper serializer\"\n            )\n        return mapping_field\n\n\nclass ReadWritePolymorphicSerializerMappingMixin(ReadOnlyPolymorphicSerializerMappingMixin):\n    def to_internal_value(self, data):\n        serializer = self.serializers_mapping.get(self.get_mapping_field())\n        if serializer is not None:\n            self.__class__ = self.serializers_cls_mapping.get(self.get_mapping_field())\n            return serializer.to_internal_value(data=data)\n        else:\n            raise Exception(f\"Cannot find a matching serializer for the specified type {self.get_mapping_field()}\")\n\n\nclass MonkeyPatchPartial:\n    \"\"\"\n    Work around bug #3847 in djangorestframework by monkey-patching the partial\n    attribute of the root serializer during the call to validate_empty_values.\n    https://github.com/encode/django-rest-framework/issues/3847\n    \"\"\"\n\n    def __init__(self, root):\n        self._root = root\n\n    def __enter__(self):\n        self._old = getattr(self._root, 'partial')\n        setattr(self._root, 'partial', False)\n\n    def __exit__(self, *args):\n        setattr(self._root, 'partial', self._old)\n\n\nclass OverrideRootPartialMixin:\n    \"\"\"\n    This mixin is used to convert a serializer into a partial serializer,\n    based on the serializer `partial` property rather than the parent's `partial` property.\n    Refer to the issue\n        https://github.com/encode/django-rest-framework/issues/3847\n    \"\"\"\n\n    def run_validation(self, *args, **kwargs):\n        if not self.partial:\n            with MonkeyPatchPartial(self.root):\n                return super().run_validation(*args, **kwargs)\n        return super().run_validation(*args, **kwargs)\n\n\nclass CustomBooleanLabelSerializer(MathesarErrorMessageMixin, serializers.Serializer):\n    TRUE = serializers.CharField()\n    FALSE = serializers.CharField()\n\n\nDISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY = 'db_type'\n\n\nclass BooleanDisplayOptionSerializer(MathesarErrorMessageMixin, OverrideRootPartialMixin, serializers.Serializer):\n    input = serializers.ChoiceField(choices=[(\"dropdown\", \"dropdown\"), (\"checkbox\", \"checkbox\")])\n    custom_labels = CustomBooleanLabelSerializer(required=False)\n\n\nclass AbstractNumberDisplayOptionSerializer(serializers.Serializer):\n    number_format = serializers.ChoiceField(allow_null=True, required=False, choices=['english', 'german', 'french', 'hindi', 'swiss'])\n\n\nclass NumberDisplayOptionSerializer(\n    MathesarErrorMessageMixin,\n    OverrideRootPartialMixin,\n    AbstractNumberDisplayOptionSerializer\n):\n    show_as_percentage = serializers.BooleanField(default=False)\n\n\nclass TimeFormatDisplayOptionSerializer(\n    MathesarErrorMessageMixin,\n    OverrideRootPartialMixin,\n    serializers.Serializer\n):\n    format = serializers.CharField(max_length=255)\n\n\nclass DurationDisplayOptionSerializer(MathesarErrorMessageMixin, OverrideRootPartialMixin, serializers.Serializer):\n    min = serializers.CharField(max_length=255)\n    max = serializers.CharField(max_length=255)\n    show_units = serializers.BooleanField()\n\n\nclass DisplayOptionsMappingSerializer(\n    MathesarErrorMessageMixin,\n    OverrideRootPartialMixin,\n    ReadWritePolymorphicSerializerMappingMixin,\n    serializers.Serializer\n):\n    serializers_mapping = {\n        MathesarTypeIdentifier.BOOLEAN.value: BooleanDisplayOptionSerializer,\n        MathesarTypeIdentifier.NUMBER.value: NumberDisplayOptionSerializer,\n        MathesarTypeIdentifier.DATETIME.value: TimeFormatDisplayOptionSerializer,\n        MathesarTypeIdentifier.DATE.value: TimeFormatDisplayOptionSerializer,\n        MathesarTypeIdentifier.TIME.value: TimeFormatDisplayOptionSerializer,\n        MathesarTypeIdentifier.DURATION.value: DurationDisplayOptionSerializer,\n    }\n\n    def get_mapping_field(self):\n        db_type = self.context[DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY]\n        mathesar_type = get_mathesar_type_from_db_type(db_type)\n        return mathesar_type\n", "path": "mathesar/api/serializers/shared_serializers.py"}], "after_files": [{"content": "from rest_framework.serializers import Serializer\nfrom rest_framework.utils.serializer_helpers import ReturnList\nfrom rest_framework_friendly_errors.mixins import FriendlyErrorMessagesMixin\nfrom django.core.exceptions import ValidationError as DjangoValidationError\nfrom rest_framework.exceptions import ValidationError as RestValidationError\nfrom mathesar.api.exceptions.generic_exceptions.base_exceptions import ErrorBody\n\n\nclass MathesarErrorMessageMixin(FriendlyErrorMessagesMixin):\n    def is_pretty(self, error):\n        return isinstance(error, dict) and tuple(error.keys()) == ErrorBody._fields\n\n    def build_pretty_errors(self, errors, serializer=None):\n\n        \"\"\"\n        This method build on top of `build_pretty_errors` method of the superclass\n        It provides the following additional features\n        1. Avoids processing prettified exceptions\n        2. Add field to the pretty exception body if raised by field validation method\n        \"\"\"\n        pretty = []\n        for error_type in errors:\n            error = errors[error_type]\n            if error_type == 'non_field_errors':\n                if self.is_pretty(error):\n                    pretty.append(error)\n                else:\n                    pretty.extend(self.get_non_field_error_entries(errors[error_type]))\n            else:\n                field = self.get_serializer_fields().fields[error_type]\n                if isinstance(field, Serializer) and type(errors[error_type]) == dict:\n                    field.initial_data = self.initial_data[error_type]\n                    child_errors = field.build_pretty_errors(errors[error_type])\n                    pretty += child_errors\n                    continue\n                if self.is_pretty(error):\n                    if 'field' not in error or error['field'] is None or str(error['field']) == 'None':\n                        error['field'] = error_type\n                    pretty.append(error)\n                else:\n                    pretty.extend(self.get_field_error_entries(errors[error_type], field))\n        if pretty:\n            return pretty\n        return []\n\n    def get_serializer_fields(self):\n        return self.fields\n\n    def _run_validator(self, validator, field, message):\n        \"\"\"\n        This method build on top of `_run_validator` method of the superclass\n        It provides the following additional features\n        1. Includes serializer if `required_context` is True similar to the behaviour of drf\n        \"\"\"\n        try:\n            args = []\n            if getattr(validator, 'requires_context', False):\n                args.append(field)\n            validator(self.initial_data[field.field_name], *args)\n        except (DjangoValidationError, RestValidationError) as err:\n            err_message = err.detail[0] if hasattr(err, 'detail') else err.message\n            return err_message == message\n\n    @property\n    def errors(self):\n        \"\"\"\n        This method build on top of `errors` property of the superclass to return a list instead of a dictionary\n        \"\"\"\n        ugly_errors = super(FriendlyErrorMessagesMixin, self).errors\n        pretty_errors = self.build_pretty_errors(ugly_errors)\n        return ReturnList(pretty_errors, serializer=self)\n\n    @property\n    def field_map(self):\n        \"\"\"\n        This method build on top of `field_map` property of the superclass\n        It provides the following additional features\n        1. Adds `ListSerializer` to `relation` field list\n        \"\"\"\n        parent_field_map = super(FriendlyErrorMessagesMixin, self).field_map\n        # Add missing `ListSerializer to existing relation list`\n        parent_field_map['relation'].append('ListSerializer')\n        return parent_field_map\n\n    def get_field_kwargs(self, field, field_data):\n        \"\"\"\n        This method build on top of `get_field_kwargs` method of the superclass\n        It provides the following fixes\n        1. Fixes file type length value to use name of the file instead of the size of the file,\n         matching the default behaviour of drf\n        \"\"\"\n        field_type = field.__class__.__name__\n        kwargs = {\n            'data_type': type(field_data).__name__\n        }\n        if field_type in self.field_map['boolean']:\n            kwargs.update({'input': field_data})\n        elif field_type in self.field_map['string']:\n            kwargs.update(\n                {\n                    'max_length': getattr(field, 'max_length', None),\n                    'min_length': getattr(field, 'min_length', None),\n                    'value': field_data\n                }\n            )\n        elif field_type in self.field_map['numeric']:\n\n            kwargs.update(\n                {\n                    'min_value': field.min_value,\n                    'max_value': field.max_value,\n                    'decimal_places': getattr(field, 'decimal_places', None),\n                    'max_decimal_places': getattr(field, 'decimal_places', None),\n                    'max_digits': getattr(field, 'max_digits', None)\n                }\n            )\n            max_digits = kwargs['max_digits']\n            decimal_places = kwargs['decimal_places']\n            if max_digits is not None and decimal_places is not None:\n                whole_digits = max_digits - decimal_places\n                kwargs.update({'max_whole_digits': whole_digits})\n        elif field_type in self.field_map['date'].keys():\n            kwargs.update({'format': self.field_map['date'][field_type]})\n        elif field_type in self.field_map['choice']:\n            kwargs.update(\n                {\n                    'input': field_data,\n                    'input_type': type(field_data).__name__\n                }\n            )\n        elif field_type in self.field_map['file']:\n            kwargs.update(\n                {\n                    'max_length': field.max_length,\n                    # Parent method calculates the length of the file instead of the filename,\n                    # we are changing it to calculate length of the file name\n                    'length': len(field.parent.data.get(field.source, '').name)\n                }\n            )\n        elif field_type in self.field_map['composite']:\n            kwargs.update(\n                {\n                    'input_type': type(field_data).__name__,\n                    'max_length': getattr(field, 'max_length', None),\n                    'min_length': getattr(field, 'min_length', None)\n                }\n            )\n        elif field_type in self.field_map['relation']:\n            kwargs.update(\n                {\n                    'pk_value': field_data,\n                    'data_type': type(field_data).__name__,\n                    'input_type': type(field_data).__name__,\n                    'slug_name': getattr(field, 'slug_field', None),\n                    'value': field_data\n                }\n            )\n        else:\n            kwargs.update({'max_length': getattr(field, 'max_length', None)})\n        return kwargs\n", "path": "mathesar/api/exceptions/mixins.py"}, {"content": "from django.core.exceptions import ImproperlyConfigured\nfrom rest_framework import serializers\n\nfrom mathesar.api.exceptions.mixins import MathesarErrorMessageMixin\nfrom mathesar.database.types import MathesarTypeIdentifier, get_mathesar_type_from_db_type\n\n\nclass ReadOnlyPolymorphicSerializerMappingMixin:\n    \"\"\"\n    This serializer mixin is helpful in serializing polymorphic models,\n    by switching to correct serializer based on the mapping field value.\n    \"\"\"\n\n    def __new__(cls, *args, **kwargs):\n        if cls.serializers_mapping is None:\n            raise ImproperlyConfigured(\n                '`{cls}` is missing a '\n                '`{cls}.model_serializer_mapping` attribute'.format(cls=cls.__name__)\n            )\n        return super().__new__(cls, *args, **kwargs)\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.serializers_cls_mapping = {}\n        serializers_mapping = self.serializers_mapping\n        self.serializers_mapping = {}\n        for identifier, serializer_cls in serializers_mapping.items():\n            if callable(serializer_cls):\n                serializer = serializer_cls(*args, **kwargs)\n                serializer.parent = self\n            else:\n                serializer = serializer_cls\n            self.serializers_mapping[identifier] = serializer\n            self.serializers_cls_mapping[identifier] = serializer_cls\n\n    def to_representation(self, instance):\n        serializer = self.serializers_mapping.get(self.get_mapping_field(), None)\n        if serializer is not None:\n            return serializer.to_representation(instance)\n        else:\n            raise Exception(f\"Cannot find a matching serializer for the specified type {self.get_mapping_field()}\")\n\n    def get_mapping_field(self):\n        mapping_field = getattr(self, \"mapping_field\", None)\n        if mapping_field is None:\n            raise Exception(\n                \"Add a `mapping_field` to be used as a identifier\"\n                \"or override this method to return a identifier to identify a proper serializer\"\n            )\n        return mapping_field\n\n\nclass ReadWritePolymorphicSerializerMappingMixin(ReadOnlyPolymorphicSerializerMappingMixin):\n    def to_internal_value(self, data):\n        serializer = self.serializers_mapping.get(self.get_mapping_field())\n        if serializer is not None:\n            return serializer.to_internal_value(data=data)\n        else:\n            raise Exception(f\"Cannot find a matching serializer for the specified type {self.get_mapping_field()}\")\n\n\nclass MonkeyPatchPartial:\n    \"\"\"\n    Work around bug #3847 in djangorestframework by monkey-patching the partial\n    attribute of the root serializer during the call to validate_empty_values.\n    https://github.com/encode/django-rest-framework/issues/3847\n    \"\"\"\n\n    def __init__(self, root):\n        self._root = root\n\n    def __enter__(self):\n        self._old = getattr(self._root, 'partial')\n        setattr(self._root, 'partial', False)\n\n    def __exit__(self, *args):\n        setattr(self._root, 'partial', self._old)\n\n\nclass OverrideRootPartialMixin:\n    \"\"\"\n    This mixin is used to convert a serializer into a partial serializer,\n    based on the serializer `partial` property rather than the parent's `partial` property.\n    Refer to the issue\n        https://github.com/encode/django-rest-framework/issues/3847\n    \"\"\"\n\n    def run_validation(self, *args, **kwargs):\n        if not self.partial:\n            with MonkeyPatchPartial(self.root):\n                return super().run_validation(*args, **kwargs)\n        return super().run_validation(*args, **kwargs)\n\n\nclass MathesarPolymorphicErrorMixin(MathesarErrorMessageMixin):\n    def get_serializer_fields(self):\n        return self.serializers_mapping[self.get_mapping_field()].fields\n\n\nclass CustomBooleanLabelSerializer(MathesarErrorMessageMixin, serializers.Serializer):\n    TRUE = serializers.CharField()\n    FALSE = serializers.CharField()\n\n\nDISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY = 'db_type'\n\n\nclass BooleanDisplayOptionSerializer(MathesarErrorMessageMixin, OverrideRootPartialMixin, serializers.Serializer):\n    input = serializers.ChoiceField(choices=[(\"dropdown\", \"dropdown\"), (\"checkbox\", \"checkbox\")])\n    custom_labels = CustomBooleanLabelSerializer(required=False)\n\n\nclass AbstractNumberDisplayOptionSerializer(serializers.Serializer):\n    number_format = serializers.ChoiceField(allow_null=True, required=False, choices=['english', 'german', 'french', 'hindi', 'swiss'])\n\n\nclass NumberDisplayOptionSerializer(\n    MathesarErrorMessageMixin,\n    OverrideRootPartialMixin,\n    AbstractNumberDisplayOptionSerializer\n):\n    show_as_percentage = serializers.BooleanField(default=False)\n\n\nclass TimeFormatDisplayOptionSerializer(\n    MathesarErrorMessageMixin,\n    OverrideRootPartialMixin,\n    serializers.Serializer\n):\n    format = serializers.CharField(max_length=255)\n\n\nclass DurationDisplayOptionSerializer(MathesarErrorMessageMixin, OverrideRootPartialMixin, serializers.Serializer):\n    min = serializers.CharField(max_length=255)\n    max = serializers.CharField(max_length=255)\n    show_units = serializers.BooleanField()\n\n\nclass DisplayOptionsMappingSerializer(\n    OverrideRootPartialMixin,\n    MathesarPolymorphicErrorMixin,\n    ReadWritePolymorphicSerializerMappingMixin,\n    serializers.Serializer\n):\n    serializers_mapping = {\n        MathesarTypeIdentifier.BOOLEAN.value: BooleanDisplayOptionSerializer,\n        MathesarTypeIdentifier.NUMBER.value: NumberDisplayOptionSerializer,\n        MathesarTypeIdentifier.DATETIME.value: TimeFormatDisplayOptionSerializer,\n        MathesarTypeIdentifier.DATE.value: TimeFormatDisplayOptionSerializer,\n        MathesarTypeIdentifier.TIME.value: TimeFormatDisplayOptionSerializer,\n        MathesarTypeIdentifier.DURATION.value: DurationDisplayOptionSerializer,\n    }\n\n    def get_mapping_field(self):\n        db_type = self.context[DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY]\n        mathesar_type = get_mathesar_type_from_db_type(db_type)\n        return mathesar_type\n", "path": "mathesar/api/serializers/shared_serializers.py"}]}