docs: def asdict(model, exclude=None, exclude_underscore=None, exclude_pk=None,
             follow=None, include=None, only=None, method='asdict', **kwargs):
      """Get a dict from a model
  
      Using the `method` parameter makes it possible to have multiple methods
      that formats the result.
  
      Additional keyword arguments will be passed to all relationships that are
      followed. This can be used to pass on things like request or context.
  
      :param follow: List or dict of relationships that should be followed.
              If the parameter is a dict the value should be a dict of \
              keyword arguments. Currently it follows InstrumentedList, \
              MappedCollection and regular 1:1, 1:m, m:m relationships. Follow \
              takes an extra argument, 'method', which is the method that \
              should be used on the relation. It also takes the extra argument \
              'parent' which determines where the relationships data should be \
              added in the response dict. If 'parent' is set the relationship \
              will be added with it's own key as a child to `parent`.
      :param exclude: List of properties that should be excluded, will be \
              merged with `model.dictalchemy_exclude`
      :param exclude_pk: If True any column that refers to the primary key will \
              be excluded.
      :param exclude_underscore: Overides `model.dictalchemy_exclude_underscore`\
              if set
      :param include: List of properties that should be included. Use this to \
              allow python properties to be called. This list will be merged \
              with `model.dictalchemy_asdict_include` or \
              `model.dictalchemy_include`.
      :param only: List of properties that should be included. This will \
              override everything else except `follow`.
      :param method: Name of the method that is currently called. This will be \
              the default method used in 'follow' unless another method is\
              set.
  
      :raises: :class:`dictalchemy.errors.MissingRelationError` \
              if `follow` contains a non-existent relationship.
      :raises: :class:`dictalchemy.errors.UnsupportedRelationError` If `follow` \
              contains an existing relationship that currently isn't supported.
  
      :returns: dict
  
      """
  
      follow = arg_to_dict(follow)
  
      info = inspect(model)
  
      columns = [c.key for c in info.mapper.column_attrs]
      synonyms = [c.key for c in info.mapper.synonyms]
  
      if only:
          attrs = only
      else:
          exclude = exclude or []
          exclude += getattr(model, 'dictalchemy_exclude',
                             constants.default_exclude) or []
          if exclude_underscore is None:
              exclude_underscore = getattr(model,
                                           'dictalchemy_exclude_underscore',
                                           constants.default_exclude_underscore)
          if exclude_underscore:
              # Exclude all properties starting with underscore
              exclude += [k.key for k in info.mapper.attrs if k.key[0] == '_']
          if exclude_pk is True:
              exclude += [c.key for c in info.mapper.primary_key]
  
          include = (include or []) + (getattr(model,
                                               'dictalchemy_asdict_include',
                                               getattr(model,
                                                       'dictalchemy_include',
                                                       None)) or [])
          attrs = [k for k in columns + synonyms + include if k not in exclude]
  
      data = dict([(k, getattr(model, k)) for k in attrs])
  
      for (rel_key, orig_args) in follow.iteritems():
  
          try:
              rel = getattr(model, rel_key)
          except AttributeError:
              raise errors.MissingRelationError(rel_key)
  
          args = copy.deepcopy(orig_args)
          method = args.pop('method', method)
          args['method'] = method
          args.update(copy.copy(kwargs))
  
          if hasattr(rel, method):
              rel_data = getattr(rel, method)(**args)
          elif isinstance(rel, (list, _AssociationList)):
              rel_data = []
  
              for child in rel:
                  if hasattr(child, method):
                      rel_data.append(getattr(child, method)(**args))
                  else:
                      try:
                          rel_data.append(dict(child))
                          # TypeError is for non-dictable children
                      except TypeError:
                          rel_data.append(copy.copy(child))
  
          elif isinstance(rel, dict):
              rel_data = {}
  
              for (child_key, child) in rel.iteritems():
                  if hasattr(child, method):
                      rel_data[child_key] = getattr(child, method)(**args)
                  else:
                      try:
                          rel_data[child_key] = dict(child)
                      except ValueError:
                          rel_data[child_key] = copy.copy(child)
  
          elif isinstance(rel, (AppenderMixin, Query)):
              rel_data = []
  
              for child in rel.all():
                  if hasattr(child, method):
                      rel_data.append(getattr(child, method)(**args))
                  else:
                      rel_data.append(dict(child))
  
          elif rel is None:
              rel_data = None
          else:
              raise errors.UnsupportedRelationError(rel_key)
  
          ins_key = args.pop('parent', None)
  
          if ins_key is None:
              data[rel_key] = rel_data
          else:
              if ins_key not in data:
                  data[ins_key] = {}
  
              data[ins_key][rel_key] = rel_data
  
      return data