11.2 first_or_404和可调用对象

1.first_or_404

视图函数接受用户填写的email账号,如果不存在应该跳转到404界面,这个逻辑flask-sqlalchemy为我们提供了良好的封装,不需要手动去处理,只需要调用Query的first_or_404()方法即可

user = User.query.filter_by(email=account_email).first_or_404()

first_or_404内部是对first函数的封装,他在获取了first的结果以后,会进行空判断,如果结果为空,则调用abort()方法,而abort()方法内部是调用了一个对象

first_or_404

    def first_or_404(self):
        """Like :meth:`first` but aborts with 404 if not found instead of returning ``None``."""

        rv = self.first()
        if rv is None:
            abort(404)
        return rv

abort()

def abort(status, *args, **kwargs):
    '''
    Raises an :py:exc:`HTTPException` for the given status code or WSGI
    application::

        abort(404)  # 404 Not Found
        abort(Response('Hello World'))

    Can be passed a WSGI application or a status code.  If a status code is
    given it's looked up in the list of exceptions and will raise that
    exception, if passed a WSGI application it will wrap it in a proxy WSGI
    exception and raise that::

       abort(404)
       abort(Response('Hello World'))

    '''
    return _aborter(status, *args, **kwargs)

_aborter = Aborter()

如果要将一个对象像函数一样调用,需要在函数内部实现__call__方法,_aborter(status, *args, **kwargs)实际上就是调用了Aborter的__call__方法

Aborter()

class Aborter(object):

    """
    When passed a dict of code -> exception items it can be used as
    callable that raises exceptions.  If the first argument to the
    callable is an integer it will be looked up in the mapping, if it's
    a WSGI application it will be raised in a proxy exception.

    The rest of the arguments are forwarded to the exception constructor.
    """

    def __init__(self, mapping=None, extra=None):
        if mapping is None:
            mapping = default_exceptions
        self.mapping = dict(mapping)
        if extra is not None:
            self.mapping.update(extra)

    def __call__(self, code, *args, **kwargs):
        if not args and not kwargs and not isinstance(code, integer_types):
            raise HTTPException(response=code)
        if code not in self.mapping:
            raise LookupError('no exception for %r' % code)
        raise self.mapping[code](*args, **kwargs)

2.可调用对象的作用

class A:
    def go(self):
        return object()


class B:
    def run(self):
        return object()


def func():
    return object()


def main(param):
    # 我想在main中传入一个参数,得到一个对象object
    # b.run()
    # a.go()
    # func()
    pass


main(A())
main(B())
main(func)

如果不适用可调用对象,我们需要在main函数中区分是不同的情况,分别处理,非常的麻烦。 如果main方法传入的参数只有方法那就好说了,我们只需要param()就可以调用,所以python为我们提供了可调用对象,让对象可以像方法一样调用,修改好的代码如下

class A:
    def __call__(self):
        return object()


class B:
    def __call__(self):
        return object()


def func():
    return object()


def main(callable):
    # 我想在main中传入一个参数,得到一个对象object
    callable()
    pass


main(A())
main(B())
main(func)

这就是可调用对象中统一调用接口的意义。在flask中有很多可调用对象的使用,如globas.py中对current_app,request等对象的封装.其中_find_app,_lookup_req_object都是可调用对象

# context locals
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, 'request'))
session = LocalProxy(partial(_lookup_req_object, 'session'))
g = LocalProxy(partial(_lookup_app_object, 'g'))

Last updated