docs: def todict(self, attrs_to_serialize=None,
                 rels_to_expand=None,
                 rels_to_serialize=None,
                 group_listrels_by=None,
                 key_modifications=None,
                 dict_struct=None,
                 dict_post_processors=None):
  
          """Converts an instance to a dictionary form
  
          Args:
  
  
              attrs_to_serialize (list of str):  The columns which should
                  be serialized as a part of the output dictionary
  
              key_modifications (dict of str,str): A dictionary used to map
                  the display names of columns whose original name we want
                  to be modified in the json
  
              rels_to_serialize (list of tuple of str):  A list of tuples. The
                  first element of the tuple is the relationship
                  that is to be serialized. The second element it the name of the
                  attribute in the related model, the value of which is to be used
                  as the representation
  
              rels_to_expand (list of str): A list of relationships to expand.
                  You can specify nested relationships by placing dots.
  
              group_listrels_by (dict of str, list of str): A dictionary
                  representing how to hierarchially group a list like relationship.
                  The relationship fields are the keys and the list of the attributes
                  based on which they are to be grouped are the values.
  
  
          """
  
          # Never replace the following code by the (attrs = attrs or
          # self._attrs_) idiom. Python considers empty list as false. So
          # even if you pass an empty list, it will take self._x_ value. But
          # we don't want that as the empty list is what we use to end
          # the recursion
          dict_struct = (
              self._dict_struct_ if dict_struct is None
              else dict_struct)
          if dict_struct is None:
              dict_struct = self.autogenerated_dict_structure()
          if dict_struct is not None:
              return self.todict_using_struct(
                  dict_struct=dict_struct,
                  dict_post_processors=dict_post_processors)
          attrs_to_serialize = (
              self._attrs_to_serialize_ if attrs_to_serialize is None
              else attrs_to_serialize)
          rels_to_serialize = (
              self._rels_to_serialize_ if rels_to_serialize is None
              else rels_to_serialize)
          rels_to_expand = (
              self._rels_to_expand_ if rels_to_expand is None
              else rels_to_expand)
          key_modifications = (
              self._key_modifications_ if key_modifications is None
              else key_modifications)
          group_listrels_by = (
              self._group_listrels_by_ if group_listrels_by is None
              else group_listrels_by)
          # Convert rels_to_expand to a dictionary
          rels_to_expand_dict = {}
          for rel in rels_to_expand:
              partitioned_rels = rel.partition('.')
              if partitioned_rels[0] not in rels_to_expand_dict:
                  rels_to_expand_dict[partitioned_rels[0]] = (
                      [partitioned_rels[-1]] if partitioned_rels[-1]
                      else [])
              else:
                  if partitioned_rels[-1]:
                      rels_to_expand_dict[partitioned_rels[0]].append(
                          partitioned_rels[-1])
  
          # # Convert grouplistrelsby to a dict
          # group_listrels_dict = {}
          # for rel_to_group, grouping_keys in group_listrels_by.iteritems():
          #     partitioned_rel_to_group = rel_to_group.partition('.')
          #     if partitioned_rel_to_group[0] not in group_listrels_dict:
          #         group_listrels_dict[partitioned_rel_to_group[0]] = (
          #             {partitioned_rel_to_group[-1]: grouping_keys}
          #             if partitioned_rel_to_group[-1] else grouping_keys)
          #     else:
          #         if partitioned_rel_to_group[-1]:
          #             group_listrels_dict[
          #                 partitioned_rel_to_group[0]][
          #                     partitioned_rel_to_group[-1]] = grouping_keys
  
          # Serialize attrs
          result = self.serialize_attrs(*attrs_to_serialize)
  
          # Serialize rels
          if len(rels_to_serialize) > 0:
              for rel, id_attr in rels_to_serialize:
                  rel_obj = getattr(self, rel) if hasattr(self, rel) else None
                  if rel_obj is not None:
                      if is_list_like(rel_obj):
                          if (group_listrels_by is not None and
                                  rel in group_listrels_by):
                              result[rel] = deep_group(
                                  rel_obj,
                                  attr_to_show=id_attr,
                                  keys=group_listrels_by[rel]
                              )
                          else:
                              result[rel] = [getattr(item, id_attr)
                                             for item in rel_obj if hasattr(item, id_attr)]
                      elif is_dict_like(rel_obj):
                          result[rel] = {k: getattr(v, id_attr)
                                         for k, v in rel_obj.iteritems()
                                         if hasattr(v, id_attr)}
                      else:
                          result[rel] = getattr(rel_obj, id_attr) if hasattr(
                              rel_obj, id_attr) else None
                  else:
                      result[rel] = None
  
          # Expand some rels
          for rel, child_rels in rels_to_expand_dict.iteritems():
              rel_obj = getattr(self, rel) if hasattr(self, rel) else None
              if rel_obj is not None:
                  if is_list_like(rel_obj):
                      if (group_listrels_by is not None and
                              rel in group_listrels_by):
                          result[rel] = deep_group(
                              rel_obj,
                              keys=group_listrels_by[rel], serializer='todict',
                              serializer_kwargs={'rels_to_expand': child_rels}
                          )
                      else:
                          result[rel] = [i.todict(rels_to_expand=child_rels)
                                         if hasattr(i, 'todict') else i
                                         for i in rel_obj]
                          # result[rel] = serialized_list(
                          #     rel_obj, rels_to_expand=child_rels)
                  elif is_dict_like(rel_obj):
                      result[rel] = {k: v.todict()
                                     if hasattr(v, 'todict') else v
                                     for k, v in rel_obj.iteritems()}
                  else:
                      result[rel] = rel_obj.todict(
                          rels_to_expand=child_rels) if hasattr(
                          rel_obj, 'todict') else rel_obj
  
          for key, mod_key in key_modifications.items():
              if key in result:
                  result[mod_key] = result.pop(key)
  
          if isinstance(dict_post_processors, list):
              for dict_post_processor in dict_post_processors:
                  if callable(dict_post_processor):
                      result = dict_post_processor(result, self)
  
          return result