99from ..remote import RemoteObject
1010
1111
12+ class ObjectAnsibleIdField (serializers .Field ):
13+ """
14+ Field for object_ansible_id that supports both annotation optimization and fallback.
15+
16+ For read operations: Uses annotation when available, falls back to manual lookup.
17+ For write operations: Converts ansible_id to object_id for internal use.
18+ """
19+
20+ def to_representation (self , obj ):
21+ """Get object_ansible_id, using annotation when available, falling back to manual lookup"""
22+ # First try to use the annotation from the queryset (for optimized list operations)
23+ if hasattr (obj , '_object_ansible_id_annotation' ) and obj ._object_ansible_id_annotation :
24+ return str (obj ._object_ansible_id_annotation )
25+
26+ # Fallback for cases where annotation is not available (creation, etc.)
27+ if not obj .content_type_id or not obj .object_id :
28+ return None
29+
30+ content_object = obj .content_object
31+ if isinstance (content_object , RemoteObject ):
32+ return None
33+ if hasattr (content_object , 'resource' ):
34+ return str (content_object .resource .ansible_id )
35+ return None
36+
37+ def to_internal_value (self , value ):
38+ """Convert object_ansible_id to object_id for internal use"""
39+ if not value :
40+ return None
41+
42+ from ansible_base .resource_registry .models import Resource
43+
44+ try :
45+ resource = Resource .objects .get (ansible_id = value )
46+ return resource .object_id
47+ except Resource .DoesNotExist :
48+ raise serializers .ValidationError ("Resource with this ansible_id does not exist." )
49+
50+
1251class DABContentTypeSerializer (serializers .ModelSerializer ):
1352 parent_content_type = serializers .SlugRelatedField (read_only = True , slug_field = 'api_slug' )
1453
@@ -32,7 +71,7 @@ class BaseAssignmentSerializer(serializers.ModelSerializer):
3271 content_type = serializers .SlugRelatedField (read_only = True , slug_field = 'api_slug' )
3372 role_definition = serializers .SlugRelatedField (slug_field = 'name' , queryset = RoleDefinition .objects .all ())
3473 created_by_ansible_id = ActorAnsibleIdField (source = 'created_by' , required = False , allow_null = True )
35- object_ansible_id = serializers . UUIDField ( read_only = True , allow_null = True )
74+ object_ansible_id = ObjectAnsibleIdField ( source = 'object_id' , required = False , allow_null = True )
3675 object_id = serializers .CharField (allow_blank = True , required = False , allow_null = True )
3776 from_service = serializers .CharField (write_only = True )
3877
@@ -44,22 +83,16 @@ def validate(self, attrs):
4483
4584 So this does the mutual validation to assure we have sufficient data.
4685 """
47- has_oid = bool (self .initial_data .get ('object_id' ))
48- has_oaid = bool (self .initial_data .get ('object_ansible_id' ))
49-
5086 rd = attrs ['role_definition' ]
87+ has_object_id = 'object_id' in attrs and attrs ['object_id' ]
88+
5189 if rd .content_type_id :
52- if not self .partial and not has_oid and not has_oaid :
90+ if not self .partial and not has_object_id :
5391 raise serializers .ValidationError ("You must provide either 'object_id' or 'object_ansible_id'." )
54- elif not has_oaid :
55- # need to remove blank and null fields or else it can overwrite the non-null non-blank field
56- attrs ['object_id' ] = self .initial_data ['object_id' ]
5792 else :
58- if has_oaid or has_oid :
93+ if has_object_id :
5994 raise serializers .ValidationError ("Can not provide either 'object_id' or 'object_ansible_id' for system role" )
6095
61- # NOTE: right now not enforcing the case you provide both, could check for consistency later
62-
6396 return super ().validate (attrs )
6497
6598 def find_existing_assignment (self , queryset ):
0 commit comments