Retrieve a Django model class for the indicated model name and app name (or module object)

    Args:
      model: A model class, queryset or string. E.g. one of:
        * derivative of django.db.models.base.ModelBase
        * derivative of django.db.models.query.QuerySet
        * string name of a django.db.models.Model class that can be found in <app>.models
      app (module): A python module (Django app) or the string name of a Django app.
      fuzziness (float): The allowable levenshtein distance between the model name. (0 < fuzziness < 1)

    Returns:
      Model: a Django model class

    TODO:
      * Parse the model string to see if it contains a model path like 
        'app_name.model_name' or 'app_name.models.model_name'

    Examples:

      >>> from django.db import transaction
      >>> transaction.rollback() 
      >>> get_model('mission', fuzziness=.7).__name__
      'Permission'
      >>> transaction.rollback() 
      >>> isinstance(get_model('ser', fuzziness=.5), djmodels.base.ModelBase)
      True
      >>> transaction.rollback() 
      >>> get_model(get_model('CaseMaster', DEFAULT_APP, fuzziness=.05)).objects.count() >= 0
      True

def get_model(model=DEFAULT_MODEL, app=None, fuzziness=False):
    """Retrieve a Django model class for the indicated model name and app name (or module object)

    Args:
      model: A model class, queryset or string. E.g. one of:
        * derivative of django.db.models.base.ModelBase
        * derivative of django.db.models.query.QuerySet
        * string name of a django.db.models.Model class that can be found in <app>.models
      app (module): A python module (Django app) or the string name of a Django app.
      fuzziness (float): The allowable levenshtein distance between the model name. (0 < fuzziness < 1)

    Returns:
      Model: a Django model class

    TODO:
      * Parse the model string to see if it contains a model path like 
        'app_name.model_name' or 'app_name.models.model_name'

    Examples:

      >>> from django.db import transaction
      >>> transaction.rollback() 
      >>> get_model('mission', fuzziness=.7).__name__
      'Permission'
      >>> transaction.rollback() 
      >>> isinstance(get_model('ser', fuzziness=.5), djmodels.base.ModelBase)
      True
      >>> transaction.rollback() 
      >>> get_model(get_model('CaseMaster', DEFAULT_APP, fuzziness=.05)).objects.count() >= 0
      True

    """
    if isinstance(model, djmodels.base.ModelBase):
        return model
    elif isinstance(model, (djmodels.Manager, djmodels.query.QuerySet)):
        return model.model
    if not app or (isinstance(model, basestring) and '.' in model):
        try:
            app, model = model.split('.')
        except:
            tokens = model.split('.')
            model = tokens[-1]
            app = '.'.join(tokens[:-1])
    # print 'getting model=%r from app=%r' % (model, app)
    try:
        # FIXME: this will turn app into a list of strings if app=None is passed in!!!
        app = get_app(app)
    except:
        pass
        # FIXME: This seems futile! model is still just a string!
        # try:
        #     app = get_app(model.app_label)
        # except:
        #     app = get_app(model._meta.app_label)
    try:
        model_object = djmodels.get_model(app.__package__.split('.')[-1], model)
        if model_object:
            return model_object
    except:
        pass
    try: 
        model_object = djmodels.get_model(app, model)
        if model_object:
            return model_object
    except:
        pass
    if not fuzziness and not model_object:
        return model_object
    app = get_app(app)
    if not app:
        return None
    model_names = [mc.__name__ for mc in djmodels.get_models(app)]
    if app and model and model_names:
        model_name, similarity_score = fuzzy.extractOne(str(model), model_names)
        if similarity_score / 100. + float(fuzziness) >= 1.0:
            return djmodels.get_model(app.__package__.split('.')[-1], model_name)