Repository: marcosschroh/dataclasses-avroschema

Issue:
RecordField default_to_avro produces non serializable output
**Describe the bug**
When having a nested model the avro_schema function of the model fails if the nested attribute contains a non json serializable field e.g. datetime.

**To Reproduce**
```python
import dataclasses
from dataclasses_avroschema import AvroModel
from datetime import datetime

@dataclasses.dataclass
class Metadata(AvroModel):
     event_time: datetime = dataclasses.field(default_factory=datetime.utcnow, default=dataclasses.MISSING)

@dataclasses.dataclass
class Record(AvroModel):
    metadata: Metadata = dataclasses.field(default_factory=lambda: Metadata(), default=dataclasses.MISSING)

Record()
# Out: Record(metadata=Metadata(event_time=datetime.datetime(2023, 8, 5, 7, 32, 27, 798392)))

Record.avro_schema()

# Fails with: TypeError: Object of type datetime is not JSON serializable
```

**Expected behavior**
Should produce the avor schema with default of datetime as string

As for my understanding it is due to `RecordField.default_to_avro` simply calling the `to_dict` function on the value provided.
As far as I can tell the `default_to_avro` is only called on rendering, so it should be fine to do `json.loads(value.to_json())` here.

Edit: fixed suggested fix to use `to_json()`

Discussion:
dabdada: This needs some rework as now it would break union types
dabdada: Changed the solution to something that renders only actual values of the default into the schema. This should work and does not break other existing stuff. 🤞🏻 

Patch:
diff --git a/dataclasses_avroschema/fields/fields.py b/dataclasses_avroschema/fields/fields.py
index b7fee26..56b3a9e 100644
--- a/dataclasses_avroschema/fields/fields.py
+++ b/dataclasses_avroschema/fields/fields.py
@@ -692,7 +692,11 @@ class RecordField(Field):
         return record_type
 
     def default_to_avro(self, value: "schema_generator.AvroModel") -> typing.Dict:
-        return value.to_dict()
+        schema_def = value.schema_def or value._generate_avro_schema()
+        return {
+            fieldname: field.default_to_avro(getattr(value, fieldname))
+            for fieldname, field in schema_def.get_fields_map().items()
+        }
 
     def fake(self) -> typing.Any:
         return self.type.fake()
diff --git a/dataclasses_avroschema/schema_definition.py b/dataclasses_avroschema/schema_definition.py
index e988ca2..50bec76 100644
--- a/dataclasses_avroschema/schema_definition.py
+++ b/dataclasses_avroschema/schema_definition.py
@@ -170,3 +170,6 @@ class AvroSchemaDefinition(BaseSchemaDefinition):
             schema["aliases"] = self.metadata.aliases
 
         return schema
+
+    def get_fields_map(self) -> typing.Dict[str, Field]:
+        return self.fields_map


Test patch:
diff --git a/tests/fields/test_BaseField.py b/tests/fields/test_BaseField.py
index d8ae238..4c913eb 100644
--- a/tests/fields/test_BaseField.py
+++ b/tests/fields/test_BaseField.py
@@ -1,4 +1,7 @@
-from dataclasses_avroschema import AvroField
+import dataclasses
+from datetime import datetime
+
+from dataclasses_avroschema import AvroField, AvroModel, utils
 
 
 def test_render():
@@ -61,3 +64,40 @@ def test_render_metadata():
     expected = [("encoding", "some_exotic_encoding"), ("doc", "Official Breed Name")]
 
     assert expected == field.get_metadata()
+
+
+def test_render_complex_types():
+    @dataclasses.dataclass
+    class Metadata(AvroModel):
+        timestamp: datetime = dataclasses.field(
+            default_factory=lambda: datetime(2023, 10, 21, 11, 11),
+        )
+
+    parent = AvroModel()
+    parent.metadata = utils.SchemaMetadata.create(type)
+    field = AvroField(
+        "metadata",
+        Metadata,
+        metadata={"desc": "Some metadata"},
+        default_factory=Metadata,
+        parent=parent,
+    )
+
+    expected = {
+        "desc": "Some metadata",
+        "name": "metadata",
+        "type": {
+            "type": "record",
+            "name": "Metadata",
+            "fields": [
+                {
+                    "name": "timestamp",
+                    "type": {"type": "long", "logicalType": "timestamp-millis"},
+                    "default": 1697886660000,
+                }
+            ],
+        },
+        "default": {"timestamp": 1697886660000},
+    }
+
+    assert expected == dict(field.render())