def to_dict( self, ignore: Union[str, List[str], Set[str]] = None, only: Union[str, List[str], Set[str]] = None, ) -> dict: ignore = make_ignore_rule_for_field(ignore) only = make_only_rule_for_field(only) return self.__to_dict(ignore, only)
def result_to_dict(result, ignore=None, only=None) -> dict: res = {} ignore_set = make_ignore_rule_for_field(ignore) only_set = make_only_rule_for_field(only) for key in result.keys(): if key not in ignore_set: if only and key not in only_set: continue v = getattr(result, key) if isinstance(v, dt.datetime) and v.tzinfo is None: v = v.replace(tzinfo=local_tz_info) res[key] = v return res
def _update_model_by_dict(model, dict_obj: dict, ignore=None, only=None, __prefix=''): mapper = sqlalchemy.inspect(model).mapper col_attrs = mapper.column_attrs relationships = mapper.relationships ignore_set = make_ignore_rule_for_field(ignore) only_set = make_only_rule_for_field(only) for key in dict_obj: if key in col_attrs or key in relationships: if _in_set(__prefix, key, ignore_set): continue if only and not _in_set(__prefix, key, only_set): continue v = dict_obj[key] if key in relationships: if isinstance(v, dict): obj = getattr(model, key) if obj: _update_model_by_dict( obj, v, ignore=ignore_set, only=only_set, __prefix=_new_prefix(__prefix, key), ) v = obj else: obj_cls = relationships[key].mapper.class_ v = _dict_to_model( v, obj_cls, ignore=ignore_set, only=only_set, __prefix=_new_prefix(__prefix, key), ) elif isinstance(v, (list, set)): # FIXME raise RuntimeError( f'do not support to update a list: "{_new_prefix(__prefix, key)}"' ) elif key in col_attrs: if isinstance(col_attrs[key].class_attribute.type, sqlalchemy.DateTime): v = convert_to_datetime(v) setattr(model, key, v)
def _dict_to_model(dict_obj: dict, model_cls, ignore=None, only=None, __prefix=''): mapper = sqlalchemy.inspect(model_cls).mapper col_attrs = mapper.column_attrs relationships = mapper.relationships ignore_set = make_ignore_rule_for_field(ignore) only_set = make_only_rule_for_field(only) kwargs = {} for key in dict_obj: if key in col_attrs or key in relationships: if _in_set(__prefix, key, ignore_set): continue if only and not _in_set(__prefix, key, only_set): continue v = dict_obj[key] if key in relationships: if isinstance(v, dict): obj_cls = relationships[key].mapper.class_ v = _dict_to_model( v, obj_cls, ignore=ignore_set, only=only_set, __prefix=_new_prefix(__prefix, key), ) elif isinstance(v, (list, set)): obj_cls = relationships[key].mapper.class_ t = [ _dict_to_model( obj, obj_cls, ignore=ignore_set, only=only_set, __prefix=_new_prefix(__prefix, key), ) for obj in v ] v = t elif key in col_attrs: if isinstance( getattr(model_cls, key).type, sqlalchemy.DateTime): v = convert_to_datetime(v) kwargs[key] = v model = model_cls(**kwargs) return model
def _model_to_dict(model, ignore=None, only=None, include=None, __prefix='', __exists=None) -> dict: if __exists is None: __exists = set() if model in __exists: raise DictRecursionError __exists.add(model) mapper = sqlalchemy.inspect(model).mapper col_attrs = mapper.column_attrs relationships = mapper.relationships d = {} ignore_set = make_ignore_rule_for_field(ignore) only_set = make_only_rule_for_field(only) include_set = make_include_rule_for_field(include) keys = list(col_attrs.keys()) for k in relationships.keys(): if _new_prefix(__prefix, k) in include_set: keys.append(k) for key in keys: if _in_set(__prefix, key, ignore_set): continue if only and not _in_set(__prefix, key, only_set): continue if key in col_attrs: v = getattr(model, key) if isinstance(v, dt.datetime) and v.tzinfo is None: v = v.replace(tzinfo=local_tz_info) d[key] = v elif key in relationships: if not hasattr(model, key): continue v = getattr(model, key) try: if v: if isinstance(v, (list, set)): t = [ _model_to_dict( obj, ignore=ignore_set, only=only_set, include=include_set, __prefix=_new_prefix(__prefix, key), __exists=__exists, ) for obj in v ] v = t else: v = _model_to_dict( v, ignore=ignore_set, only=only_set, include=include_set, __prefix=_new_prefix(__prefix, key), __exists=__exists, ) d[key] = v except DictRecursionError: pass __exists.remove(model) return d
def test_make_only_rule(): assert make_only_rule_for_field('a.b') == {'a', 'a.b'}
def _make_only_rule(only: Union[str, List[str], Set[str]]) -> dict: return _expand_rule_set(make_only_rule_for_field(only))