@@ -334,7 +334,7 @@ def __iter__(self):
334334 if isinstance (cur_attr , Record ):
335335 yield i , dict (cur_attr )
336336 elif isinstance (cur_attr , list ) and all (
337- isinstance (i , Record ) for i in cur_attr
337+ isinstance (i , ( Record , GenericListObject ) ) for i in cur_attr
338338 ):
339339 yield i , [dict (x ) for x in cur_attr ]
340340 else :
@@ -394,10 +394,9 @@ def generic_list_parser(key_name, list_item):
394394 and "object" in list_item
395395 ):
396396 lookup = list_item ["object_type" ]
397- model = None
398- model = CONTENT_TYPE_MAPPER .get (lookup )
399- if model :
400- return model (list_item ["object" ], self .api , self .endpoint )
397+ if model := CONTENT_TYPE_MAPPER .get (lookup , None ):
398+ record = model (list_item ["object" ], self .api , self .endpoint )
399+ return GenericListObject (record )
401400
402401 return list_item
403402
@@ -433,7 +432,7 @@ def list_parser(key_name, list_item):
433432 # check if GFK
434433 if len (v ) and isinstance (v [0 ], dict ) and "object_type" in v [0 ]:
435434 v = [generic_list_parser (k , i ) for i in v ]
436- to_cache = list ( v )
435+ to_cache = [ i . serialize () for i in v ]
437436 elif k == "constraints" :
438437 # Permissions constraints can be either dict or list
439438 to_cache = copy .deepcopy (v )
@@ -491,6 +490,7 @@ def serialize(self, nested=False, init=False):
491490 If an attribute's value is a ``Record`` type it's replaced with
492491 the ``id`` field of that object.
493492
493+
494494 .. note::
495495
496496 Using this to get a dictionary representation of the record
@@ -506,6 +506,7 @@ def serialize(self, nested=False, init=False):
506506 init_vals = dict (self ._init_cache )
507507
508508 ret = {}
509+
509510 for i in dict (self ):
510511 current_val = getattr (self , i ) if not init else init_vals .get (i )
511512 if i == "custom_fields" :
@@ -515,15 +516,21 @@ def serialize(self, nested=False, init=False):
515516 current_val = getattr (current_val , "serialize" )(nested = True )
516517
517518 if isinstance (current_val , list ):
518- current_val = [
519- v .id if isinstance (v , Record ) else v for v in current_val
520- ]
519+ serialized_list = []
520+ for v in current_val :
521+ if isinstance (v , GenericListObject ):
522+ v = v .serialize ()
523+ elif isinstance (v , Record ):
524+ v = v .id
525+ serialized_list .append (v )
526+ current_val = serialized_list
521527 if i in LIST_AS_SET and (
522528 all ([isinstance (v , str ) for v in current_val ])
523529 or all ([isinstance (v , int ) for v in current_val ])
524530 ):
525531 current_val = list (OrderedDict .fromkeys (current_val ))
526532 ret [i ] = current_val
533+
527534 return ret
528535
529536 def _diff (self ):
@@ -636,3 +643,29 @@ def delete(self):
636643 http_session = self .api .http_session ,
637644 )
638645 return True if req .delete () else False
646+
647+
648+ class GenericListObject :
649+ def __init__ (self , record ):
650+ from pynetbox .models .mapper import TYPE_CONTENT_MAPPER
651+
652+ self .object = record
653+ self .object_id = record .id
654+ self .object_type = TYPE_CONTENT_MAPPER .get (record .__class__ )
655+
656+ def __repr__ (self ):
657+ return str (self .object )
658+
659+ def serialize (self ):
660+ ret = {k : getattr (self , k ) for k in ["object_id" , "object_type" ]}
661+ return ret
662+
663+ def __getattr__ (self , k ):
664+ return getattr (self .object , k )
665+
666+ def __iter__ (self ):
667+ for i in ["object_id" , "object_type" , "object" ]:
668+ cur_attr = getattr (self , i )
669+ if isinstance (cur_attr , Record ):
670+ cur_attr = dict (cur_attr )
671+ yield i , cur_attr
0 commit comments