Repository: koxudaxi/datamodel-code-generator

Issue:
JSON Schema `const` value and type ignored when setting defaults for Pydantic V2
**Describe the bug**
Use of `--force-optional` clobbers `--use-one-literal-as-default`. In my opinion `--force-optional` should use defaults where they exist and only fall back to assigning to `None` where they don't exist.

### Input

```json
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "title": "Force optional demo",
    "properties": {
        "foo": {
            "const": "foo"
        }
    }
}
```

### Used command
```
datamodel-codegen --input force-optional-demo.json --output-model-type pydantic_v2.BaseModel --force-optional --use-one-literal-as-default
```

### Actual output

```python
# generated by datamodel-codegen:
#   filename:  force-optional-demo.json
#   timestamp: 2023-12-05T15:06:01+00:00

from __future__ import annotations

from pydantic import BaseModel
from typing_extensions import Literal


class ForceOptionalDemo(BaseModel):
    foo: Literal['foo'] = None
```

### Expected output

```python
# generated by datamodel-codegen:
#   filename:  force-optional-demo.json
#   timestamp: 2023-12-05T15:06:01+00:00

from __future__ import annotations

from pydantic import BaseModel
from typing_extensions import Literal


class ForceOptionalDemo(BaseModel):
    foo: Literal['foo'] = 'foo'
```


Discussion:

Resolving patch:
diff --git a/datamodel_code_generator/model/pydantic_v2/base_model.py b/datamodel_code_generator/model/pydantic_v2/base_model.py
--- a/datamodel_code_generator/model/pydantic_v2/base_model.py
+++ b/datamodel_code_generator/model/pydantic_v2/base_model.py
@@ -87,10 +87,9 @@ def process_const(self) -> None:
         self.const = True
         self.nullable = False
         const = self.extras['const']
-        if self.data_type.type == 'str' and isinstance(
-            const, str
-        ):  # pragma: no cover # Literal supports only str
-            self.data_type = self.data_type.__class__(literals=[const])
+        self.data_type = self.data_type.__class__(literals=[const])
+        if not self.default:
+            self.default = const
 
     def _process_data_in_str(self, data: Dict[str, Any]) -> None:
         if self.const:
@@ -103,7 +102,7 @@ def _process_data_in_str(self, data: Dict[str, Any]) -> None:
     def _process_annotated_field_arguments(
         self, field_arguments: List[str]
     ) -> List[str]:
-        if not self.required:
+        if not self.required or self.const:
             if self.use_default_kwarg:
                 return [
                     f'default={repr(self.default)}',


Test patch:
diff --git a/tests/data/expected/main/use_default_with_const/output.py b/tests/data/expected/main/use_default_with_const/output.py
new file mode 100644
--- /dev/null
+++ b/tests/data/expected/main/use_default_with_const/output.py
@@ -0,0 +1,12 @@
+# generated by datamodel-codegen:
+#   filename:  use_default_with_const.json
+#   timestamp: 2019-07-26T00:00:00+00:00
+
+from __future__ import annotations
+
+from pydantic import BaseModel
+from typing_extensions import Literal
+
+
+class UseDefaultWithConst(BaseModel):
+    foo: Literal['foo'] = 'foo'
diff --git a/tests/data/jsonschema/use_default_with_const.json b/tests/data/jsonschema/use_default_with_const.json
new file mode 100644
--- /dev/null
+++ b/tests/data/jsonschema/use_default_with_const.json
@@ -0,0 +1,10 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema#",
+    "type": "object",
+    "title": "Use default with const",
+    "properties": {
+        "foo": {
+            "const": "foo"
+        }
+    }
+}
diff --git a/tests/test_main.py b/tests/test_main.py
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -1264,6 +1264,28 @@ def test_force_optional():
         )
 
 
+@freeze_time('2019-07-26')
+def test_use_default_pydantic_v2_with_json_schema_const():
+    with TemporaryDirectory() as output_dir:
+        output_file: Path = Path(output_dir) / 'output.py'
+        return_code: Exit = main(
+            [
+                '--input',
+                str(JSON_SCHEMA_DATA_PATH / 'use_default_with_const.json'),
+                '--output',
+                str(output_file),
+                '--output-model-type',
+                'pydantic_v2.BaseModel',
+                '--use-default',
+            ]
+        )
+        assert return_code == Exit.OK
+        assert (
+            output_file.read_text()
+            == (EXPECTED_MAIN_PATH / 'use_default_with_const' / 'output.py').read_text()
+        )
+
+
 @freeze_time('2019-07-26')
 def test_main_with_exclusive():
     with TemporaryDirectory() as output_dir: