@@ -334,7 +334,7 @@ def __iter__(self):
334
334
if isinstance (cur_attr , Record ):
335
335
yield i , dict (cur_attr )
336
336
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
338
338
):
339
339
yield i , [dict (x ) for x in cur_attr ]
340
340
else :
@@ -394,10 +394,9 @@ def generic_list_parser(key_name, list_item):
394
394
and "object" in list_item
395
395
):
396
396
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 )
401
400
402
401
return list_item
403
402
@@ -433,7 +432,7 @@ def list_parser(key_name, list_item):
433
432
# check if GFK
434
433
if len (v ) and isinstance (v [0 ], dict ) and "object_type" in v [0 ]:
435
434
v = [generic_list_parser (k , i ) for i in v ]
436
- to_cache = list ( v )
435
+ to_cache = [ i . serialize () for i in v ]
437
436
elif k == "constraints" :
438
437
# Permissions constraints can be either dict or list
439
438
to_cache = copy .deepcopy (v )
@@ -491,6 +490,7 @@ def serialize(self, nested=False, init=False):
491
490
If an attribute's value is a ``Record`` type it's replaced with
492
491
the ``id`` field of that object.
493
492
493
+
494
494
.. note::
495
495
496
496
Using this to get a dictionary representation of the record
@@ -506,6 +506,7 @@ def serialize(self, nested=False, init=False):
506
506
init_vals = dict (self ._init_cache )
507
507
508
508
ret = {}
509
+
509
510
for i in dict (self ):
510
511
current_val = getattr (self , i ) if not init else init_vals .get (i )
511
512
if i == "custom_fields" :
@@ -515,15 +516,21 @@ def serialize(self, nested=False, init=False):
515
516
current_val = getattr (current_val , "serialize" )(nested = True )
516
517
517
518
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
521
527
if i in LIST_AS_SET and (
522
528
all ([isinstance (v , str ) for v in current_val ])
523
529
or all ([isinstance (v , int ) for v in current_val ])
524
530
):
525
531
current_val = list (OrderedDict .fromkeys (current_val ))
526
532
ret [i ] = current_val
533
+
527
534
return ret
528
535
529
536
def _diff (self ):
@@ -636,3 +643,29 @@ def delete(self):
636
643
http_session = self .api .http_session ,
637
644
)
638
645
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