tetra-framework / tetra

Tetra - A full stack component framework for Django using Alpine.js
https://www.tetraframework.com
MIT License
540 stars 14 forks source link

TypeError: Object of type xxis not JSON serializable #13

Closed PatrickSchutte closed 2 years ago

PatrickSchutte commented 2 years ago

Good morning Sam,

I don't know if this should be addressed in Tetra or I must work around it. I have a object which gives me the above error when rendering. When I serialize it in the console, I get the same error, but am able to get around it with y = json.dumps(x, default=str)

@dataclass
class CalendarDay:
    id: int
    day: datetime.date
    client: User

I have attached my incomplete playing around for your perusal. (I'm using PyCharm, so my HTML is separate) pat.zip

edit: I'm currently working around this with this change in your tetra.utils.py:

def to_json(obj):

    return json.dumps(obj, cls=TetraJSONEncoder, default=str)
samwillis commented 2 years ago

Hi @PatrickSchutte,

Thanks, I will take a look at your project.

So as you have spotted, so far public attributes or values passed to client methods need to be JSON serializable with a few extras (dates, times and sets).

I really like the idea of adding dataclass support where all attributes are themselves searalizable with our extended JSON format. I will have a think about how best to do that as it needs a corresponding JS object type...

Currently I haven't added support to serialise Django Models, it's quite a complicated problem as the sealable format needs to be symmetrical. I.e. we need to be able to reverse it to get back to the original Python objects, your default=str will break on public attributes when resuming a component. I have considered adding support for Model instances but it will need to have a corresponding client JavaScript object type that functions the same as django.model, with all of it's field options and validation, but I have decided not to add it for now as it a very big job.

In general it's better to just make the model attributes you want to be avalible to the client JS public properties.

However, one of the next jobs on my to do list is a ModelComponent which will allow you to make selected model fields public along with some useful CRUD helpers.

PatrickSchutte commented 2 years ago

Hi @samwillis Thanks for your reply, I basically realised this after I posted it so I am working around it. I think I have broken something else with my code that used to work before, so will go through it again. I am now getting an error when I select the next month:

Internal Server Error: /tetra/appointment/calendar/month_component/select_day
Traceback (most recent call last):
  File "G:\python\latcare\venv\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
  File "G:\python\latcare\venv\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "G:\python\latcare\venv\lib\site-packages\tetra\views.py", line 36, in component_method
    return component._call_public_method(
  File "G:\python\latcare\venv\lib\site-packages\tetra\components\base.py", line 536, in _call_public_method
    result = getattr(self, method_name)(*args)
  File "G:\python\latcare\venv\lib\site-packages\tetra\components\base.py", line 233, in fn
    self.update()
  File "G:\python\latcare\venv\lib\site-packages\tetra\components\base.py", line 528, in update
    self.update_html(include_state=True)
  File "G:\python\latcare\venv\lib\site-packages\tetra\components\base.py", line 520, in update_html
    self.client._updateHtml(self.render(data=RenderData.UPDATE))
AttributeError: 'int' object has no attribute '_updateHtml'
[14/Jun/2022 09:57:30] "POST /tetra/appointment/calendar/month_component/select_day HTTP/1.1" 500 98740
PatrickSchutte commented 2 years ago

Hi @samwillis Thanks for your reply, I basically realised this after I posted it so I am working around it. I think I have broken something else with my code that used to work before, so will go through it again. I am now getting an error when I select the next month:

Internal Server Error: /tetra/appointment/calendar/month_component/select_day
Traceback (most recent call last):
  File "G:\python\latcare\venv\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
  File "G:\python\latcare\venv\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "G:\python\latcare\venv\lib\site-packages\tetra\views.py", line 36, in component_method
    return component._call_public_method(
  File "G:\python\latcare\venv\lib\site-packages\tetra\components\base.py", line 536, in _call_public_method
    result = getattr(self, method_name)(*args)
  File "G:\python\latcare\venv\lib\site-packages\tetra\components\base.py", line 233, in fn
    self.update()
  File "G:\python\latcare\venv\lib\site-packages\tetra\components\base.py", line 528, in update
    self.update_html(include_state=True)
  File "G:\python\latcare\venv\lib\site-packages\tetra\components\base.py", line 520, in update_html
    self.client._updateHtml(self.render(data=RenderData.UPDATE))
AttributeError: 'int' object has no attribute '_updateHtml'
[14/Jun/2022 09:57:30] "POST /tetra/appointment/calendar/month_component/select_day HTTP/1.1" 500 98740

Sorted! I had used client as one of my variables but it is actually a Tetra reserved word. Changing it to customer solved the issue.