import functools def rgetattr(obj, attr: str, safe: bool = False, *args, **kwargs): """ Version récursive de getattr pour utiliser une propriété chaînée même avec None au milieu. exemples : - rgetattr(obj, 'a.b.c') - rgetattr(obj, 'a.b.c', safe=True) :param obj: cible :type obj: Any :param attr: propriété qui peut être chaînée en séparant par '.' :type attr: str :param safe: indique qu'il faut tester la présence de l'attribut avec hasattr (utile pour les relations entre modèles Django), defaults to False :type safe: bool :return: valeur de l'attribut :rtype: Any """ def _getattr(obj, attr): return getattr(obj, attr, *args) if not safe or hasattr(obj, attr) else None return functools.reduce(_getattr, [obj] + attr.split('.')) def safe_rgetattr(obj, attr: str, safe: bool = False, *args, **kwargs): """ version safe de rgetattr exemples : safe_rgetattr(obj, 'a.b.c') """ return rgetattr(obj, attr, safe=True, *args, **kwargs)