<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def fromdict(model, data, exclude=None, exclude_underscore=None, allow_pk=None, follow=None, include=None, only=None):
 """Update a model from a dict Works almost identically as :meth:`dictalchemy.utils.asdict`. However, it will not create missing instances or update collections. This method updates the following properties on a model: * Simple columns * Synonyms * Simple 1-m relationships :param data: dict of data :param exclude: list of properties that should be excluded :param exclude_underscore: If True underscore properties will be excluded,\ if set to None model.dictalchemy_exclude_underscore will be used. :param allow_pk: If True any column that refers to the primary key will \ be excluded. Defaults model.dictalchemy_fromdict_allow_pk or \ dictable.constants.fromdict_allow_pk. If set to True a primary \ key can still be excluded with the `exclude` parameter. :param follow: Dict of relations that should be followed, the key is the \ arguments passed to the relation. Relations only works on simple \ relations, not on lists. :param include: List of properties that should be included. This list \ will override anything in the exclude list. It will not override \ allow_pk. :param only: List of the only properties that should be set. This \ will not override `allow_pk` or `follow`. :raises: :class:`dictalchemy.errors.DictalchemyError` If a primary key is \ in data and allow_pk is False :returns: The model """


    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]
    relations = [c.key for c in info.mapper.relationships]
    primary_keys = [c.key for c in info.mapper.primary_key]

    if allow_pk is None:
        allow_pk = getattr(model, 'dictalchemy_fromdict_allow_pk',
                           constants.default_fromdict_allow_pk)

    if only:
        valid_keys = 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] == '_']

        include = (include or []) + (getattr(model,
                                             'dictalchemy_fromdict_include',
                                             getattr(model,
                                                     'dictalchemy_include',
                                                     None)) or [])
        valid_keys = [k for k in columns + synonyms
                      if k not in exclude] + include

    # Keys that will be updated
    update_keys = set(valid_keys) & set(data.keys())

    # Check for primary keys
    data_primary_key= update_keys & set(primary_keys)
    if len(data_primary_key) and not allow_pk:
        msg = ("Primary keys({0}) cannot be updated by fromdict."
               "Set 'dictalchemy_fromdict_allow_pk' to True in your Model"
               " or pass 'allow_pk=True'.").format(','.join(data_primary_key))
        raise errors.DictalchemyError(msg)

    # Update columns and synonyms
    for k in update_keys:
        setattr(model, k, data[k])

    # Update simple relations
    for (k, args) in follow.iteritems():
        if k not in data:
            continue
        if k not in relations:
            raise errors.MissingRelationError(k)
        rel = getattr(model, k)
        if hasattr(rel, 'fromdict'):
            rel.fromdict(data[k], **args)

    return model