From f27804b85bebd7be1891761e97c5a26f2767a63d Mon Sep 17 00:00:00 2001 From: Brandon Shar Date: Sun, 26 Jan 2025 20:10:00 -0500 Subject: [PATCH 1/2] Add InertiaMeta for automatic serialization --- README.md | 24 ++++++++++++++++++++++++ inertia/tests/test_encoder.py | 22 +++++++++++++++++++++- inertia/tests/testapp/models.py | 9 +++++++++ inertia/utils.py | 6 ++++++ 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a32c4a8..676c7a9 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,30 @@ def inertia_share(get_response): return get_response(request) return middleware ``` +### Prop Serialization + +Unlike Rails and Laravel, Django does not handle converting objects to JSON by default so Inertia Django offers two different ways to handle prop serialization. + +#### InertiaJsonEncoder + +The default behavior is via the InertiaJsonEncoder. The InertiaJsonEncoder is a barebones implementation +that extends the DjangoJSONEncoder with the ability to handle QuerySets and models. Models are JSON encoded +via Django's `model_to_dict` method excluding the field `password`. This method has limitations though, as +`model_to_dict` does not include fields where editable=False (such as automatic timestamps). + +#### InertiaMeta + +Starting in Inertia Django v1.2, Inertia Django supports an InertiaMeta nested class. Similar to Django Rest Framework's serializers, any class (not just models) can contain an InertiaMeta class which can specify how that class should be serialized to JSON. At this time, in only supports `fields`, but this may be extended in future versions. + +```python +class User(models.Model): + name = models.CharField(max_length=255) + password = models.CharField(max_length=255) + created_at = models.DateField(auto_now_add=True) + + class InertiaMeta: + fields = ('name', 'created_at') +``` ### External Redirects diff --git a/inertia/tests/test_encoder.py b/inertia/tests/test_encoder.py index 4972126..c7f3b7e 100644 --- a/inertia/tests/test_encoder.py +++ b/inertia/tests/test_encoder.py @@ -3,7 +3,7 @@ from django.test import TestCase -from inertia.tests.testapp.models import User +from inertia.tests.testapp.models import Sport, User from inertia.utils import InertiaJsonEncoder @@ -31,6 +31,26 @@ def test_it_handles_models_with_dates_and_removes_passwords(self): self.encode(user), ) + def test_it_handles_inertia_meta_fields(self): + sport = Sport( + id=3, + name="Hockey", + season="Winter", + created_at=datetime(2022, 10, 31, 10, 13, 1), + ) + + self.assertEqual( + dumps( + { + "id": 3, + "name": "Hockey", + "created_at": "2022-10-31T10:13:01", + } + ), + self.encode(sport) + ) + + def test_it_handles_querysets(self): User( name="Brandon", diff --git a/inertia/tests/testapp/models.py b/inertia/tests/testapp/models.py index 545e87b..4c5dc67 100644 --- a/inertia/tests/testapp/models.py +++ b/inertia/tests/testapp/models.py @@ -6,3 +6,12 @@ class User(models.Model): password = models.CharField(max_length=255) birthdate = models.DateField() registered_at = models.DateTimeField() + created_at = models.DateField(auto_now_add=True) + +class Sport(models.Model): + name = models.CharField(max_length=255) + season = models.CharField(max_length=255) + created_at = models.DateField(auto_now_add=True) + + class InertiaMeta: + fields = ('id', 'name', 'created_at') diff --git a/inertia/utils.py b/inertia/utils.py index 9efa61a..05bf773 100644 --- a/inertia/utils.py +++ b/inertia/utils.py @@ -14,6 +14,12 @@ def model_to_dict(model): class InertiaJsonEncoder(DjangoJSONEncoder): def default(self, value): + if hasattr(value.__class__, 'InertiaMeta'): + return { + field: getattr(value, field) + for field in value.__class__.InertiaMeta.fields + } + if isinstance(value, models.Model): return model_to_dict(value) From 2b28d7dc46bc6a24b8543eb17798b413f451c3e7 Mon Sep 17 00:00:00 2001 From: Brandon Shar Date: Sun, 26 Jan 2025 20:15:04 -0500 Subject: [PATCH 2/2] ruff format --- inertia/tests/test_encoder.py | 3 +-- inertia/tests/testapp/models.py | 3 ++- inertia/utils.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/inertia/tests/test_encoder.py b/inertia/tests/test_encoder.py index c7f3b7e..3bd8cec 100644 --- a/inertia/tests/test_encoder.py +++ b/inertia/tests/test_encoder.py @@ -47,10 +47,9 @@ def test_it_handles_inertia_meta_fields(self): "created_at": "2022-10-31T10:13:01", } ), - self.encode(sport) + self.encode(sport), ) - def test_it_handles_querysets(self): User( name="Brandon", diff --git a/inertia/tests/testapp/models.py b/inertia/tests/testapp/models.py index 4c5dc67..cc2e2c6 100644 --- a/inertia/tests/testapp/models.py +++ b/inertia/tests/testapp/models.py @@ -8,10 +8,11 @@ class User(models.Model): registered_at = models.DateTimeField() created_at = models.DateField(auto_now_add=True) + class Sport(models.Model): name = models.CharField(max_length=255) season = models.CharField(max_length=255) created_at = models.DateField(auto_now_add=True) class InertiaMeta: - fields = ('id', 'name', 'created_at') + fields = ("id", "name", "created_at") diff --git a/inertia/utils.py b/inertia/utils.py index 05bf773..96dd695 100644 --- a/inertia/utils.py +++ b/inertia/utils.py @@ -14,7 +14,7 @@ def model_to_dict(model): class InertiaJsonEncoder(DjangoJSONEncoder): def default(self, value): - if hasattr(value.__class__, 'InertiaMeta'): + if hasattr(value.__class__, "InertiaMeta"): return { field: getattr(value, field) for field in value.__class__.InertiaMeta.fields