Fancy way to update `obj` with `data` dict.

    Parameters
    ----------
    obj : Django model instance
    data
        The data to update ``obj`` with
    update_fields
        Use your ``update_fields`` instead of our generated one. If you need
        an auto_now or auto_now_add field to get updated, set this to ``None``
        to get the default Django behavior.
    save
        If save=False, then don't actually save. This can be useful if you
        just want to utilize the verbose logging.
        DEPRECRATED in favor of the more standard ``update_fields=[]``

    Returns
    -------
    bool
        True if data changed

def obj_update(obj, data: dict, *, update_fields=UNSET, save: bool=True) -> bool:
    """
    Fancy way to update `obj` with `data` dict.

    Parameters
    ----------
    obj : Django model instance
    data
        The data to update ``obj`` with
    update_fields
        Use your ``update_fields`` instead of our generated one. If you need
        an auto_now or auto_now_add field to get updated, set this to ``None``
        to get the default Django behavior.
    save
        If save=False, then don't actually save. This can be useful if you
        just want to utilize the verbose logging.
        DEPRECRATED in favor of the more standard ``update_fields=[]``

    Returns
    -------
    bool
        True if data changed
    """
    for field_name, value in data.items():
        set_field(obj, field_name, value)
    dirty_data = getattr(obj, DIRTY, None)
    if not dirty_data:
        return False

    logger.debug(
        human_log_formatter(dirty_data),
        extra={
            'model': obj._meta.object_name,
            'pk': obj.pk,
            'changes': json_log_formatter(dirty_data),
        }
    )
    if update_fields == UNSET:
        update_fields = list(map(itemgetter('field_name'), dirty_data))
    if not save:
        update_fields = ()
    obj.save(update_fields=update_fields)
    delattr(obj, DIRTY)
    return True