Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serialization/encoding data does not work with models #64

Open
nerdoc opened this issue Jun 2, 2024 · 2 comments
Open

Serialization/encoding data does not work with models #64

nerdoc opened this issue Jun 2, 2024 · 2 comments

Comments

@nerdoc
Copy link
Collaborator

nerdoc commented Jun 2, 2024

Maybe I am misunderstanding something. There are 2 classes in utils.py: TetraJSONEncoder and TetraJSONDecoder. In theory, the purpose is clear, and I already extended both to handle models:

        ...
        elif isinstance(o, models.Model):
            return {
                "__type": f"model.{o._meta.app_label}.{o.__class__.__name__}",
                "value": o.pk,

But no matter how hard I debug tetra, I NEVER get the TetraJSONEncoder.default() method to get called. It is never, ever called.
In

return json.dumps(obj, cls=TetraJSONEncoder)
TetraJSONEncoder is used, but internally, only .encode() is called, and never .default().

Is there anything I am missing?

@samwillis have you got a clue here? Maybe I did not fully understand the serialization workflow of Tetra.

@nerdoc
Copy link
Collaborator Author

nerdoc commented Jun 2, 2024

I am adding unittests for the TetraJSONEncoder/Decoders.

@samwillis, you wrote TetraJSONEncoder that is a subclass of json.JSONEncoder, but your docstring says it is based on DjangoJSONEncoder. You were copying some of the code there, and extending the return value with a __type hint within a dict, so you could decode it later easier. DjangoJSONEncoder always returns a str, TetraJSONEncoder a str or a dict[str, Any] - or everything the json.JSONEncoder supports (simple python objects).

Generally speaking, I tried to create a mermaid diagram - mainly to understand things better.

graph TD;

subgraph python[Plain Python objects]
int
str
wrongModel[Model]
end

subgraph special[Special objects]
Model
datetime
end

JSONDecoder --> wrongModel
wrongModel --> TypeError
int  --> JSONEncoder
str --> JSONEncoder
JSONEncoder --> JSON-object
Model --> TetraJSONEncoder
datetime --> TetraJSONEncoder
TetraJSONEncoder --> JSON-object

subgraph serialized[JSON object]
JSON-object
end

JSON-object --> JSONDecoder
JSON-object --> TetraJSONDecoder
JSONDecoder --> str 
JSONDecoder --> int 
TetraJSONDecoder --> Model
TetraJSONDecoder --> datetime
Loading

I already added model support to it:

        elif isinstance(obj, models.Model):
            return {
                "__type": f"model.{obj._meta.app_label}.{obj.__class__.__name__}",
                "value": obj.pk,
            }

After a few tests, I would want to merge two others that seem to be added in the meantime to Django:

        elif isinstance(obj, datetime.timedelta):
            return duration_iso_string(obj)
        elif isinstance(obj, (decimal.Decimal, uuid.UUID, Promise)):
            return str(obj)

The tests that I created showed that when I encode and decode a simple model, it works flawlessly.

But I have problems in a form that has a ForeignKey field despite the Js/Alpine data structure holding the correct index key of the model, it is not retrieved, and I can't see that the TetraJSONDecoder is ever called, when e.g. calling the "submit" method of the component.

I'm stuck here.

@nerdoc
Copy link
Collaborator Author

nerdoc commented Jun 2, 2024

And on:
The TetraJSONDecoder decodes the object when e.g. calling a method from the frontend/javascript: The TetraJSONDecoder.object_hook it receives is a dict like this:

{'key': None, 'account_type': 1, 'country': 'AT', 'federal_state': '1', 'title': None, 'company_name': None, 
'health_service_type': 'doc', 'medical_speciality': 'gp', 'phone_number': None, 'comment': None, 
'identity_proof': None, 'profession_proof': None, 'first_name': None, 'last_name': None, 'email': None, 
'terms_conditions': True}

this is a dict, and no special one with a __type - just normal dict, which AFAIK will get fed into the component's data directly.

Maybe then my way of encoding the data is completely wrong, see above in #64 (comment).

Because the TetraJSONEncoder.default() never gets a model - but always a dict. And for simple str, int, dict objects, default() is never called.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant