@@ -262,6 +262,21 @@ def json_to_simplenamespace(model_data: dict[str, dict[str, typing.Any]], key: s
262262 return resolved_models [key ]
263263
264264
265+ def _apply_related_diff (manager : models .manager .BaseManager , field_name : str , identifiers : list [str ]) -> None :
266+ related_model_instances = [identifier_to_model (item ) for item in identifiers ]
267+ if None in related_model_instances :
268+ raise ValueError (f"One or more related models not found for identifiers: { identifiers } " )
269+
270+ if {item .pk for item in manager .all ()} == {item .pk for item in related_model_instances }:
271+ return
272+
273+ # 역참조 FK의 remove()는 Django가 field.null=True일 때만 제공하므로, 그 외에는 구성원 변경을 적용할 수 없다.
274+ if not hasattr (manager , "remove" ):
275+ raise ValueError (f"Cannot change members of the non-nullable reverse relation '{ field_name } '" )
276+
277+ manager .set (related_model_instances )
278+
279+
265280def apply_diff_to_model (models_data : dict [str , dict [str , typing .Any ]]) -> list [models .Model ]:
266281 result_instances : list [models .Model ] = []
267282
@@ -285,20 +300,11 @@ def apply_diff_to_model(models_data: dict[str, dict[str, typing.Any]]) -> list[m
285300 if not (related_model_instance := identifier_to_model (value )):
286301 raise ValueError (f"Related model not found for identifier: { value } " )
287302 setattr (model_instance , field_name , related_model_instance )
288- elif isinstance (value , collections .abc .Iterable ) and value and all (is_identifier (item ) for item in value ):
289- # If the value is a list of model identifiers, resolve them to model instances
290- related_model_instances = [identifier_to_model (item ) for item in value ]
291- if None in related_model_instances :
292- raise ValueError (f"One or more related models not found for identifiers: { value } " )
293-
294- old_related_models = {item .pk : item for item in getattr (model_instance , field_name , [])}
295- new_related_models = {item .pk : item for item in related_model_instances }
296-
297- field = getattr (model_instance , field_name )
298- for del_pk in old_related_models .keys () - new_related_models .keys ():
299- field .remove (old_related_models [del_pk ])
300- for add_pk in new_related_models .keys () - old_related_models .keys ():
301- field .add (new_related_models [add_pk ])
303+ elif is_identifier_list (value ) and isinstance (
304+ related_manager := getattr (model_instance , field_name , None ), models .manager .BaseManager
305+ ):
306+ # If the value is a list of model identifiers, it is an m2m/reverse relation
307+ _apply_related_diff (related_manager , field_name , value )
302308 else :
303309 setattr (model_instance , field_name , value )
304310
0 commit comments