From 2a30d72f1ecc8fccba84d00735884842ca1fbe14 Mon Sep 17 00:00:00 2001 From: Derek Loewen Date: Thu, 25 Jul 2024 12:14:55 -0500 Subject: [PATCH] Improve serialization performance for Odoo 17 Replacing fields_get_keys with fields_get results in a large performance penalty (more than 10x slower in some testing). This is due to the fields_get method having more logic and functionality than necessary, and being extended by various models in Odoo. This change simply provides `_fields` from the model similar to previous Odoo versions. --- controllers/serializers.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/controllers/serializers.py b/controllers/serializers.py index 3d73aa2..9b54691 100644 --- a/controllers/serializers.py +++ b/controllers/serializers.py @@ -13,6 +13,10 @@ def __init__(self, record, query="{*}", many=False): self._raw_query = query super().__init__() + @classmethod + def fields_get_keys(cls, rec): + return rec._fields + def get_parsed_restql_query(self): parser = Parser(self._raw_query) try: @@ -38,11 +42,13 @@ def data(self): @classmethod def build_flat_field(cls, rec, field_name): - all_fields = rec.fields_get() + all_fields = cls.fields_get_keys(rec) if field_name not in all_fields: msg = "'%s' field is not found" % field_name raise LookupError(msg) - field_type = rec.fields_get(field_name).get(field_name).get('type') + + field = all_fields.get(field_name, None) + field_type = getattr(field, 'type', None) if field_type in ['one2many', 'many2many']: return { field_name: [record.id for record in rec[field_name]] @@ -63,16 +69,19 @@ def build_flat_field(cls, rec, field_name): } elif field_type == "binary" and isinstance(rec[field_name], bytes) and rec[field_name]: return {field_name: rec[field_name].decode("utf-8")} + elif field_type == "binary" and isinstance(rec[field_name], bytes) and not rec[field_name]: + return {field_name: False} else: return {field_name: rec[field_name]} @classmethod def build_nested_field(cls, rec, field_name, nested_parsed_query): - all_fields = rec.fields_get() + all_fields = cls.fields_get_keys(rec) if field_name not in all_fields: msg = "'%s' field is not found" % field_name raise LookupError(msg) - field_type = rec.fields_get(field_name).get(field_name).get('type') + field = all_fields.get(field_name, None) + field_type = getattr(field, 'type', None) if field_type in ['one2many', 'many2many']: return { field_name: [ @@ -100,7 +109,7 @@ def serialize(cls, rec, parsed_query): # is used to store nested fields when the exclude operator(-) is used if parsed_query["exclude"]: # Exclude fields from a query - all_fields = rec.fields_get() + all_fields = cls.fields_get_keys(rec) for field in parsed_query["include"]: if field == "*": continue @@ -122,7 +131,7 @@ def serialize(cls, rec, parsed_query): # is empty which means the exclude operator(-) is not used, # so self.parsed_restql_query["include"] contains only fields # to include - all_fields = rec.fields_get() + all_fields = cls.fields_get_keys(rec) if "*" in parsed_query['include']: # Include all fields parsed_query['include'] = filter( @@ -143,9 +152,10 @@ def serialize(cls, rec, parsed_query): data.update(built_nested_field) else: flat_field = cls.build_flat_field(rec, field) + data.update(flat_field) else: # The query is empty i.e query={} # return nothing return {} - return data \ No newline at end of file + return data