@@ -396,6 +396,8 @@ def _dict(self):
396396class EntityFieldMeta (ABCMeta ):
397397 """A metaclass for entity fields, which adds a `fields` class attribute."""
398398
399+ _model_fields_cache : t .Dict [t .Type [BaseModel ], QbFields ] = {}
400+
399401 def __init__ (cls , name , bases , classdict ):
400402 super ().__init__ (name , bases , classdict )
401403
@@ -404,12 +406,17 @@ def __init__(cls, name, bases, classdict):
404406 if current_fields is not None and not isinstance (current_fields , QbFields ):
405407 raise ValueError (f"class '{ cls } ' already has a `fields` attribute set" )
406408
407- fields = {}
408-
409409 # If the class has an attribute ``Model`` that is a subclass of :class:`pydantic.BaseModel`, parse the model
410410 # fields to build up the ``fields`` class attribute, which is used to allow specifying ``QueryBuilder`` filters
411411 # programmatically.
412412 if hasattr (cls , 'Model' ) and issubclass (cls .Model , BaseModel ):
413+ # If the class has a ``Model``, check if we have already parsed it and cached
414+ # the result. Use the cached result if available.
415+ cache = cls ._model_fields_cache
416+ if cls .Model in cache :
417+ cls .fields = cache [cls .Model ]
418+ return
419+
413420 # If the class itself directly specifies the ``Model`` attribute, check that it is valid. Here, the check
414421 # ``cls.__dict__`` is used instead of ``hasattr`` as the former only returns true if the class itself
415422 # defines the attribute and does not just inherit it from a base class. In that case, this check will
@@ -461,17 +468,22 @@ def __init__(cls, name, bases, classdict):
461468 f'`class Model({ ", " .join (sorted (bases ))} ):`'
462469 )
463470
464- for key , field in cls . Model . model_fields . items ():
465- fields [ key ] = add_field (
471+ fields = {
472+ key : add_field (
466473 key ,
467474 alias = get_metadata (field , 'alias' , None ),
468475 dtype = field .annotation ,
469476 doc = field .description ,
470477 is_attribute = get_metadata (field , 'is_attribute' , False ),
471478 is_subscriptable = get_metadata (field , 'is_subscriptable' , False ),
472479 )
480+ for key , field in cls .Model .model_fields .items ()
481+ }
473482
474- cls .fields = QbFields ({key : fields [key ] for key in sorted (fields )})
483+ cls .fields = QbFields ({key : fields [key ] for key in sorted (fields )})
484+ cls ._model_fields_cache [cls .Model ] = cls .fields
485+ else :
486+ cls .fields = QbFields ()
475487
476488
477489class QbFieldArguments (t .TypedDict ):
0 commit comments