9
9
from ..remote import RemoteObject
10
10
11
11
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
+
12
51
class DABContentTypeSerializer (serializers .ModelSerializer ):
13
52
parent_content_type = serializers .SlugRelatedField (read_only = True , slug_field = 'api_slug' )
14
53
@@ -32,7 +71,7 @@ class BaseAssignmentSerializer(serializers.ModelSerializer):
32
71
content_type = serializers .SlugRelatedField (read_only = True , slug_field = 'api_slug' )
33
72
role_definition = serializers .SlugRelatedField (slug_field = 'name' , queryset = RoleDefinition .objects .all ())
34
73
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 )
36
75
object_id = serializers .CharField (allow_blank = True , required = False , allow_null = True )
37
76
from_service = serializers .CharField (write_only = True )
38
77
@@ -44,22 +83,16 @@ def validate(self, attrs):
44
83
45
84
So this does the mutual validation to assure we have sufficient data.
46
85
"""
47
- has_oid = bool (self .initial_data .get ('object_id' ))
48
- has_oaid = bool (self .initial_data .get ('object_ansible_id' ))
49
-
50
86
rd = attrs ['role_definition' ]
87
+ has_object_id = 'object_id' in attrs and attrs ['object_id' ]
88
+
51
89
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 :
53
91
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' ]
57
92
else :
58
- if has_oaid or has_oid :
93
+ if has_object_id :
59
94
raise serializers .ValidationError ("Can not provide either 'object_id' or 'object_ansible_id' for system role" )
60
95
61
- # NOTE: right now not enforcing the case you provide both, could check for consistency later
62
-
63
96
return super ().validate (attrs )
64
97
65
98
def find_existing_assignment (self , queryset ):
0 commit comments