We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Hide grouping separators by default in Number columns
## Current behavior

- We default to displaying grouping separators (e.g. `1,234`) in _all_ numbers.
- Users can turn off grouping separators by customizing their display options.
- This "on-by-default" behavior, feels a bit strange for columns like primary keys and years, where users typically don't see grouping separators.
- During import, Mathesar uses the `numeric` type by default -- even if all values within the import data can be cast to integers. @mathemancer explained that we made this decision early on in order to be flexible, and I think it's worth sticking with it. But it means that years don't get imported as integers by default, making it hard to take the approach were heading towards with the discussion in #1527.
- The back end does not set the grouping separator display option during import. It only gets set via the front end if the user manually adjust it.

## Desired behavior

- When the user has not configured any display options:
    - Columns with a UI type of "Number" will be rendered without grouping separators (regardless of their Postgres type). This means that the user will need to manually turn them on sometimes.
    - Columns with a UI type of "Money" will be rendered _with_ grouping separators. The user can turn them off if needed.



--- 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/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.api.exceptions.validation_exceptions.exceptions import IncompatibleFractionDigitValuesAPIException
6 from mathesar.database.types import UIType, get_ui_type_from_db_type
7 
8 
9 class ReadOnlyPolymorphicSerializerMappingMixin:
10     """
11     This serializer mixin is helpful in serializing polymorphic models,
12     by switching to correct serializer based on the mapping field value.
13     """
14     default_serializer = None
15 
16     def __new__(cls, *args, **kwargs):
17         if cls.serializers_mapping is None:
18             raise ImproperlyConfigured(
19                 '`{cls}` is missing a '
20                 '`{cls}.model_serializer_mapping` attribute'.format(cls=cls.__name__)
21             )
22         return super().__new__(cls, *args, **kwargs)
23 
24     def _init_serializer(self, serializer_cls, *args, **kwargs):
25         if callable(serializer_cls):
26             serializer = serializer_cls(*args, **kwargs)
27             serializer.parent = self
28         else:
29             serializer = serializer_cls
30         return serializer
31 
32     def __init__(self, *args, **kwargs):
33         super().__init__(*args, **kwargs)
34         self.serializers_cls_mapping = {}
35         serializers_mapping = self.serializers_mapping
36         self.serializers_mapping = {}
37         if self.default_serializer is not None:
38             self.default_serializer = self._init_serializer(self.default_serializer, *args, **kwargs)
39         for identifier, serializer_cls in serializers_mapping.items():
40             serializer = self._init_serializer(serializer_cls, *args, **kwargs)
41             self.serializers_mapping[identifier] = serializer
42             self.serializers_cls_mapping[identifier] = serializer_cls
43 
44     def get_serializer_class(self, identifier):
45         if identifier in self.serializers_mapping:
46             return self.serializers_mapping.get(identifier)
47         else:
48             return self.default_serializer
49 
50     def to_representation(self, instance):
51         serializer = self.get_serializer_class(self.get_mapping_field(instance))
52         if serializer is not None:
53             return serializer.to_representation(instance)
54         else:
55             return instance
56 
57     def get_mapping_field(self, data):
58         mapping_field = getattr(self, "mapping_field", None)
59         if mapping_field is None:
60             raise Exception(
61                 "Add a `mapping_field` to be used as a identifier"
62                 "or override this method to return a identifier to identify a proper serializer"
63             )
64         return mapping_field
65 
66 
67 class ReadWritePolymorphicSerializerMappingMixin(ReadOnlyPolymorphicSerializerMappingMixin):
68     def to_internal_value(self, data):
69         serializer = self.get_serializer_class(self.get_mapping_field(data))
70         if serializer is not None:
71             return serializer.to_internal_value(data=data)
72         else:
73             data = {}
74             return data
75 
76     def validate(self, attrs):
77         serializer = self.serializers_mapping.get(self.get_mapping_field(attrs))
78         if serializer is not None:
79             return serializer.validate(attrs)
80         return {}
81 
82 
83 class MonkeyPatchPartial:
84     """
85     Work around bug #3847 in djangorestframework by monkey-patching the partial
86     attribute of the root serializer during the call to validate_empty_values.
87     https://github.com/encode/django-rest-framework/issues/3847
88     """
89 
90     def __init__(self, root):
91         self._root = root
92 
93     def __enter__(self):
94         self._old = getattr(self._root, 'partial')
95         setattr(self._root, 'partial', False)
96 
97     def __exit__(self, *args):
98         setattr(self._root, 'partial', self._old)
99 
100 
101 class OverrideRootPartialMixin:
102     """
103     This mixin is used to convert a serializer into a partial serializer,
104     based on the serializer `partial` property rather than the parent's `partial` property.
105     Refer to the issue
106         https://github.com/encode/django-rest-framework/issues/3847
107     """
108 
109     def run_validation(self, *args, **kwargs):
110         if not self.partial:
111             with MonkeyPatchPartial(self.root):
112                 return super().run_validation(*args, **kwargs)
113         return super().run_validation(*args, **kwargs)
114 
115 
116 class MathesarPolymorphicErrorMixin(MathesarErrorMessageMixin):
117     def get_serializer_fields(self, data):
118         return self.serializers_mapping[self.get_mapping_field(data)].fields
119 
120 
121 class BaseDisplayOptionsSerializer(MathesarErrorMessageMixin, OverrideRootPartialMixin, serializers.Serializer):
122     pass
123 
124 
125 class CustomBooleanLabelSerializer(MathesarErrorMessageMixin, serializers.Serializer):
126     TRUE = serializers.CharField()
127     FALSE = serializers.CharField()
128 
129 
130 # This is the key which will determine which display options serializer is used. Its value is
131 # supposed to be the column's DB type (a DatabaseType instance).
132 DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY = 'db_type'
133 
134 
135 class BooleanDisplayOptionSerializer(BaseDisplayOptionsSerializer):
136     input = serializers.ChoiceField(choices=[("dropdown", "dropdown"), ("checkbox", "checkbox")])
137     custom_labels = CustomBooleanLabelSerializer(required=False)
138 
139 
140 FRACTION_DIGITS_CONFIG = {
141     "required": False,
142     "allow_null": True,
143     "min_value": 0,
144     "max_value": 20
145 }
146 """
147 Max value of 20 is taken from [Intl.NumberFormat docs][1].
148 
149 [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat
150 """
151 
152 
153 class AbstractNumberDisplayOptionSerializer(BaseDisplayOptionsSerializer):
154     number_format = serializers.ChoiceField(
155         required=False,
156         allow_null=True,
157         choices=['english', 'german', 'french', 'hindi', 'swiss']
158     )
159 
160     use_grouping = serializers.ChoiceField(required=False, choices=['true', 'false', 'auto'], default='auto')
161     """
162     The choices here correspond to the options available for the `useGrouping`
163     property within the [Intl API][1]. True and False are encoded as strings
164     instead of booleans to maintain consistency with the Intl API and to keep
165     the type consistent. We did considering using an optional boolean but
166     decided a string would be better, especially if we want to support other
167     options eventually, like "min2".
168 
169     [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat
170     """
171 
172     minimum_fraction_digits = serializers.IntegerField(**FRACTION_DIGITS_CONFIG)
173     maximum_fraction_digits = serializers.IntegerField(**FRACTION_DIGITS_CONFIG)
174 
175     def _validate_fraction_digits(self, data):
176         minimum = data.get("minimum_fraction_digits")
177         maximum = data.get("maximum_fraction_digits")
178         if minimum is None or maximum is None:
179             # No errors if one of the fields is not set
180             return
181         if minimum > maximum:
182             raise IncompatibleFractionDigitValuesAPIException()
183 
184     def validate(self, data):
185         self._validate_fraction_digits(data)
186         return data
187 
188 
189 class NumberDisplayOptionSerializer(AbstractNumberDisplayOptionSerializer):
190     show_as_percentage = serializers.BooleanField(default=False)
191 
192 
193 class MoneyDisplayOptionSerializer(AbstractNumberDisplayOptionSerializer):
194     currency_symbol = serializers.CharField()
195     currency_symbol_location = serializers.ChoiceField(choices=['after-minus', 'end-with-space'])
196 
197 
198 class TimeFormatDisplayOptionSerializer(BaseDisplayOptionsSerializer):
199     format = serializers.CharField(max_length=255)
200 
201 
202 class DateTimeFormatDisplayOptionSerializer(BaseDisplayOptionsSerializer):
203     time_format = serializers.CharField(max_length=255)
204     date_format = serializers.CharField(max_length=255)
205 
206 
207 class DurationDisplayOptionSerializer(BaseDisplayOptionsSerializer):
208     min = serializers.CharField(max_length=255)
209     max = serializers.CharField(max_length=255)
210     show_units = serializers.BooleanField()
211 
212 
213 class DisplayOptionsMappingSerializer(
214     OverrideRootPartialMixin,
215     MathesarPolymorphicErrorMixin,
216     ReadWritePolymorphicSerializerMappingMixin,
217     serializers.Serializer
218 ):
219     serializers_mapping = {
220         UIType.BOOLEAN: BooleanDisplayOptionSerializer,
221         UIType.NUMBER: NumberDisplayOptionSerializer,
222         UIType.DATETIME: DateTimeFormatDisplayOptionSerializer,
223         UIType.DATE: TimeFormatDisplayOptionSerializer,
224         UIType.TIME: TimeFormatDisplayOptionSerializer,
225         UIType.DURATION: DurationDisplayOptionSerializer,
226         UIType.MONEY: MoneyDisplayOptionSerializer,
227     }
228     default_serializer = BaseDisplayOptionsSerializer
229 
230     def get_mapping_field(self, _):
231         return self._get_ui_type_of_column_being_serialized()
232 
233     def _get_ui_type_of_column_being_serialized(self):
234         db_type = self.context[DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY]
235         ui_type = get_ui_type_from_db_type(db_type)
236         return ui_type
237
```
--- 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/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
@@ -157,7 +157,7 @@
         choices=['english', 'german', 'french', 'hindi', 'swiss']
     )
 
-    use_grouping = serializers.ChoiceField(required=False, choices=['true', 'false', 'auto'], default='auto')
+    use_grouping = serializers.ChoiceField(required=False, choices=['true', 'false'], default='false')
     """
     The choices here correspond to the options available for the `useGrouping`
     property within the [Intl API][1]. True and False are encoded as strings

{"golden_diff": "diff --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@@ -157,7 +157,7 @@\n         choices=['english', 'german', 'french', 'hindi', 'swiss']\n     )\n \n-    use_grouping = serializers.ChoiceField(required=False, choices=['true', 'false', 'auto'], default='auto')\n+    use_grouping = serializers.ChoiceField(required=False, choices=['true', 'false'], default='false')\n     \"\"\"\n     The choices here correspond to the options available for the `useGrouping`\n     property within the [Intl API][1]. True and False are encoded as strings\n", "issue": "Hide grouping separators by default in Number columns\n## Current behavior\r\n\r\n- We default to displaying grouping separators (e.g. `1,234`) in _all_ numbers.\r\n- Users can turn off grouping separators by customizing their display options.\r\n- This \"on-by-default\" behavior, feels a bit strange for columns like primary keys and years, where users typically don't see grouping separators.\r\n- During import, Mathesar uses the `numeric` type by default -- even if all values within the import data can be cast to integers. @mathemancer explained that we made this decision early on in order to be flexible, and I think it's worth sticking with it. But it means that years don't get imported as integers by default, making it hard to take the approach were heading towards with the discussion in #1527.\r\n- The back end does not set the grouping separator display option during import. It only gets set via the front end if the user manually adjust it.\r\n\r\n## Desired behavior\r\n\r\n- When the user has not configured any display options:\r\n    - Columns with a UI type of \"Number\" will be rendered without grouping separators (regardless of their Postgres type). This means that the user will need to manually turn them on sometimes.\r\n    - Columns with a UI type of \"Money\" will be rendered _with_ grouping separators. The user can turn them off if needed.\r\n\r\n\n", "before_files": [{"content": "from django.core.exceptions import ImproperlyConfigured\nfrom rest_framework import serializers\n\nfrom mathesar.api.exceptions.mixins import MathesarErrorMessageMixin\nfrom mathesar.api.exceptions.validation_exceptions.exceptions import IncompatibleFractionDigitValuesAPIException\nfrom mathesar.database.types import UIType, get_ui_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    default_serializer = None\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_serializer(self, serializer_cls, *args, **kwargs):\n        if callable(serializer_cls):\n            serializer = serializer_cls(*args, **kwargs)\n            serializer.parent = self\n        else:\n            serializer = serializer_cls\n        return serializer\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        if self.default_serializer is not None:\n            self.default_serializer = self._init_serializer(self.default_serializer, *args, **kwargs)\n        for identifier, serializer_cls in serializers_mapping.items():\n            serializer = self._init_serializer(serializer_cls, *args, **kwargs)\n            self.serializers_mapping[identifier] = serializer\n            self.serializers_cls_mapping[identifier] = serializer_cls\n\n    def get_serializer_class(self, identifier):\n        if identifier in self.serializers_mapping:\n            return self.serializers_mapping.get(identifier)\n        else:\n            return self.default_serializer\n\n    def to_representation(self, instance):\n        serializer = self.get_serializer_class(self.get_mapping_field(instance))\n        if serializer is not None:\n            return serializer.to_representation(instance)\n        else:\n            return instance\n\n    def get_mapping_field(self, data):\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.get_serializer_class(self.get_mapping_field(data))\n        if serializer is not None:\n            return serializer.to_internal_value(data=data)\n        else:\n            data = {}\n            return data\n\n    def validate(self, attrs):\n        serializer = self.serializers_mapping.get(self.get_mapping_field(attrs))\n        if serializer is not None:\n            return serializer.validate(attrs)\n        return {}\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, data):\n        return self.serializers_mapping[self.get_mapping_field(data)].fields\n\n\nclass BaseDisplayOptionsSerializer(MathesarErrorMessageMixin, OverrideRootPartialMixin, serializers.Serializer):\n    pass\n\n\nclass CustomBooleanLabelSerializer(MathesarErrorMessageMixin, serializers.Serializer):\n    TRUE = serializers.CharField()\n    FALSE = serializers.CharField()\n\n\n# This is the key which will determine which display options serializer is used. Its value is\n# supposed to be the column's DB type (a DatabaseType instance).\nDISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY = 'db_type'\n\n\nclass BooleanDisplayOptionSerializer(BaseDisplayOptionsSerializer):\n    input = serializers.ChoiceField(choices=[(\"dropdown\", \"dropdown\"), (\"checkbox\", \"checkbox\")])\n    custom_labels = CustomBooleanLabelSerializer(required=False)\n\n\nFRACTION_DIGITS_CONFIG = {\n    \"required\": False,\n    \"allow_null\": True,\n    \"min_value\": 0,\n    \"max_value\": 20\n}\n\"\"\"\nMax value of 20 is taken from [Intl.NumberFormat docs][1].\n\n[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat\n\"\"\"\n\n\nclass AbstractNumberDisplayOptionSerializer(BaseDisplayOptionsSerializer):\n    number_format = serializers.ChoiceField(\n        required=False,\n        allow_null=True,\n        choices=['english', 'german', 'french', 'hindi', 'swiss']\n    )\n\n    use_grouping = serializers.ChoiceField(required=False, choices=['true', 'false', 'auto'], default='auto')\n    \"\"\"\n    The choices here correspond to the options available for the `useGrouping`\n    property within the [Intl API][1]. True and False are encoded as strings\n    instead of booleans to maintain consistency with the Intl API and to keep\n    the type consistent. We did considering using an optional boolean but\n    decided a string would be better, especially if we want to support other\n    options eventually, like \"min2\".\n\n    [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat\n    \"\"\"\n\n    minimum_fraction_digits = serializers.IntegerField(**FRACTION_DIGITS_CONFIG)\n    maximum_fraction_digits = serializers.IntegerField(**FRACTION_DIGITS_CONFIG)\n\n    def _validate_fraction_digits(self, data):\n        minimum = data.get(\"minimum_fraction_digits\")\n        maximum = data.get(\"maximum_fraction_digits\")\n        if minimum is None or maximum is None:\n            # No errors if one of the fields is not set\n            return\n        if minimum > maximum:\n            raise IncompatibleFractionDigitValuesAPIException()\n\n    def validate(self, data):\n        self._validate_fraction_digits(data)\n        return data\n\n\nclass NumberDisplayOptionSerializer(AbstractNumberDisplayOptionSerializer):\n    show_as_percentage = serializers.BooleanField(default=False)\n\n\nclass MoneyDisplayOptionSerializer(AbstractNumberDisplayOptionSerializer):\n    currency_symbol = serializers.CharField()\n    currency_symbol_location = serializers.ChoiceField(choices=['after-minus', 'end-with-space'])\n\n\nclass TimeFormatDisplayOptionSerializer(BaseDisplayOptionsSerializer):\n    format = serializers.CharField(max_length=255)\n\n\nclass DateTimeFormatDisplayOptionSerializer(BaseDisplayOptionsSerializer):\n    time_format = serializers.CharField(max_length=255)\n    date_format = serializers.CharField(max_length=255)\n\n\nclass DurationDisplayOptionSerializer(BaseDisplayOptionsSerializer):\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        UIType.BOOLEAN: BooleanDisplayOptionSerializer,\n        UIType.NUMBER: NumberDisplayOptionSerializer,\n        UIType.DATETIME: DateTimeFormatDisplayOptionSerializer,\n        UIType.DATE: TimeFormatDisplayOptionSerializer,\n        UIType.TIME: TimeFormatDisplayOptionSerializer,\n        UIType.DURATION: DurationDisplayOptionSerializer,\n        UIType.MONEY: MoneyDisplayOptionSerializer,\n    }\n    default_serializer = BaseDisplayOptionsSerializer\n\n    def get_mapping_field(self, _):\n        return self._get_ui_type_of_column_being_serialized()\n\n    def _get_ui_type_of_column_being_serialized(self):\n        db_type = self.context[DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY]\n        ui_type = get_ui_type_from_db_type(db_type)\n        return ui_type\n", "path": "mathesar/api/serializers/shared_serializers.py"}], "after_files": [{"content": "from django.core.exceptions import ImproperlyConfigured\nfrom rest_framework import serializers\n\nfrom mathesar.api.exceptions.mixins import MathesarErrorMessageMixin\nfrom mathesar.api.exceptions.validation_exceptions.exceptions import IncompatibleFractionDigitValuesAPIException\nfrom mathesar.database.types import UIType, get_ui_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    default_serializer = None\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_serializer(self, serializer_cls, *args, **kwargs):\n        if callable(serializer_cls):\n            serializer = serializer_cls(*args, **kwargs)\n            serializer.parent = self\n        else:\n            serializer = serializer_cls\n        return serializer\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        if self.default_serializer is not None:\n            self.default_serializer = self._init_serializer(self.default_serializer, *args, **kwargs)\n        for identifier, serializer_cls in serializers_mapping.items():\n            serializer = self._init_serializer(serializer_cls, *args, **kwargs)\n            self.serializers_mapping[identifier] = serializer\n            self.serializers_cls_mapping[identifier] = serializer_cls\n\n    def get_serializer_class(self, identifier):\n        if identifier in self.serializers_mapping:\n            return self.serializers_mapping.get(identifier)\n        else:\n            return self.default_serializer\n\n    def to_representation(self, instance):\n        serializer = self.get_serializer_class(self.get_mapping_field(instance))\n        if serializer is not None:\n            return serializer.to_representation(instance)\n        else:\n            return instance\n\n    def get_mapping_field(self, data):\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.get_serializer_class(self.get_mapping_field(data))\n        if serializer is not None:\n            return serializer.to_internal_value(data=data)\n        else:\n            data = {}\n            return data\n\n    def validate(self, attrs):\n        serializer = self.serializers_mapping.get(self.get_mapping_field(attrs))\n        if serializer is not None:\n            return serializer.validate(attrs)\n        return {}\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, data):\n        return self.serializers_mapping[self.get_mapping_field(data)].fields\n\n\nclass BaseDisplayOptionsSerializer(MathesarErrorMessageMixin, OverrideRootPartialMixin, serializers.Serializer):\n    pass\n\n\nclass CustomBooleanLabelSerializer(MathesarErrorMessageMixin, serializers.Serializer):\n    TRUE = serializers.CharField()\n    FALSE = serializers.CharField()\n\n\n# This is the key which will determine which display options serializer is used. Its value is\n# supposed to be the column's DB type (a DatabaseType instance).\nDISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY = 'db_type'\n\n\nclass BooleanDisplayOptionSerializer(BaseDisplayOptionsSerializer):\n    input = serializers.ChoiceField(choices=[(\"dropdown\", \"dropdown\"), (\"checkbox\", \"checkbox\")])\n    custom_labels = CustomBooleanLabelSerializer(required=False)\n\n\nFRACTION_DIGITS_CONFIG = {\n    \"required\": False,\n    \"allow_null\": True,\n    \"min_value\": 0,\n    \"max_value\": 20\n}\n\"\"\"\nMax value of 20 is taken from [Intl.NumberFormat docs][1].\n\n[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat\n\"\"\"\n\n\nclass AbstractNumberDisplayOptionSerializer(BaseDisplayOptionsSerializer):\n    number_format = serializers.ChoiceField(\n        required=False,\n        allow_null=True,\n        choices=['english', 'german', 'french', 'hindi', 'swiss']\n    )\n\n    use_grouping = serializers.ChoiceField(required=False, choices=['true', 'false'], default='false')\n    \"\"\"\n    The choices here correspond to the options available for the `useGrouping`\n    property within the [Intl API][1]. True and False are encoded as strings\n    instead of booleans to maintain consistency with the Intl API and to keep\n    the type consistent. We did considering using an optional boolean but\n    decided a string would be better, especially if we want to support other\n    options eventually, like \"min2\".\n\n    [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat\n    \"\"\"\n\n    minimum_fraction_digits = serializers.IntegerField(**FRACTION_DIGITS_CONFIG)\n    maximum_fraction_digits = serializers.IntegerField(**FRACTION_DIGITS_CONFIG)\n\n    def _validate_fraction_digits(self, data):\n        minimum = data.get(\"minimum_fraction_digits\")\n        maximum = data.get(\"maximum_fraction_digits\")\n        if minimum is None or maximum is None:\n            # No errors if one of the fields is not set\n            return\n        if minimum > maximum:\n            raise IncompatibleFractionDigitValuesAPIException()\n\n    def validate(self, data):\n        self._validate_fraction_digits(data)\n        return data\n\n\nclass NumberDisplayOptionSerializer(AbstractNumberDisplayOptionSerializer):\n    show_as_percentage = serializers.BooleanField(default=False)\n\n\nclass MoneyDisplayOptionSerializer(AbstractNumberDisplayOptionSerializer):\n    currency_symbol = serializers.CharField()\n    currency_symbol_location = serializers.ChoiceField(choices=['after-minus', 'end-with-space'])\n\n\nclass TimeFormatDisplayOptionSerializer(BaseDisplayOptionsSerializer):\n    format = serializers.CharField(max_length=255)\n\n\nclass DateTimeFormatDisplayOptionSerializer(BaseDisplayOptionsSerializer):\n    time_format = serializers.CharField(max_length=255)\n    date_format = serializers.CharField(max_length=255)\n\n\nclass DurationDisplayOptionSerializer(BaseDisplayOptionsSerializer):\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        UIType.BOOLEAN: BooleanDisplayOptionSerializer,\n        UIType.NUMBER: NumberDisplayOptionSerializer,\n        UIType.DATETIME: DateTimeFormatDisplayOptionSerializer,\n        UIType.DATE: TimeFormatDisplayOptionSerializer,\n        UIType.TIME: TimeFormatDisplayOptionSerializer,\n        UIType.DURATION: DurationDisplayOptionSerializer,\n        UIType.MONEY: MoneyDisplayOptionSerializer,\n    }\n    default_serializer = BaseDisplayOptionsSerializer\n\n    def get_mapping_field(self, _):\n        return self._get_ui_type_of_column_being_serialized()\n\n    def _get_ui_type_of_column_being_serialized(self):\n        db_type = self.context[DISPLAY_OPTIONS_SERIALIZER_MAPPING_KEY]\n        ui_type = get_ui_type_from_db_type(db_type)\n        return ui_type\n", "path": "mathesar/api/serializers/shared_serializers.py"}]}