【问题标题】:Python object instance is not being saved in Flask application contextPython 对象实例未保存在 Flask 应用程序上下文中
【发布时间】:2019-03-06 14:25:03
【问题描述】:

我制作了简单的 Flask 扩展,包装 Google API Client for Python:

class ProximityBeaconAPI:
    '''
    Simple Flask extension for accessing Google Proxmity Beacon API.
    https://developers.google.com/resources/api-libraries/documentation/proximitybeacon/v1beta1/python/latest/
    '''

    def __init__(self, app=None, credentials=None):
        if app:
            self.init_app(app)
        if credentials:
            self.init_api(credentials)

    def init_app(self, app):
        '''
        Initialize Flask app for extension
        '''
        self.app = app
        self._project_id = app.config.PROJECT_ID

    @property
    def is_initialized(self):
        '''
        Checks if Proximity Beacon API is initialized.

        :return: bool
        '''
        ctx = _app_ctx_stack.top
        return hasattr(ctx, 'proximitybeaconapi')


    def init_api(self, credentials):
        ''' Initialize Proximity Beacon API

        :param credentials: google.oauth2.credentials.Credentials object  
        '''
        proximitybeaconapi = discovery.build(
            OAUTH2.API_NAME, OAUTH2.API_VERSION, credentials=credentials)
        ctx = _app_ctx_stack.top
        if ctx is not None:
            if not hasattr(ctx, 'proximitybeaconapi'):
                ctx.proximitybeaconapi = proximitybeaconapi

    def get_utoken(self):
        ''' Checks if for beacon with given name u_token attachment
        is set.

        :param beacon_name: name of the beacon
        :param namespace: namespace
        '''
        beacon_name = self.get_default_auth_beacon_name()
        ctx = _app_ctx_stack.top
        namespace = self.get_default_project_namespace().split('/')[1]
        namespaced_type = '{}/u_token'.format(namespace)
        query = {
            'beaconName': beacon_name,
            'namespacedType': namespaced_type
        }
        resp = ctx.proximitybeaconapi.beacons().attachments().list(**query).execute()
        b64_data = resp['attachments'][0]['data']
        return self._base64_to_str(b64_data)

    def is_utoken_valid(self, u_token):
        ''' Checks if recieved token is valid with current
        u_token attachment.

        :param u_token: incomming u_token
        :return: True or False
        '''
        incomming_token = self._base64_to_str(u_token)
        current_token = self.get_utoken()
        return incomming_token == current_token

在我的 oauth2 回调视图中,我通过调用基于凭据创建 API 客户端实例的 init_api 方法来初始化 Google API:

def init_api(self, credentials):
     ''' Initialize Proximity Beacon API
     :param credentials: google.oauth2.credentials.Credentials object  
     '''
     proximitybeaconapi = discovery.build(
         OAUTH2.API_NAME, OAUTH2.API_VERSION, credentials=credentials)
     ctx = _app_ctx_stack.top
     if ctx is not None:
         if not hasattr(ctx, 'proximitybeaconapi'):
             ctx.proximitybeaconapi = proximitybeaconapi

然后在我的另一个端点中调用方法get_token,该方法使用已初始化的早期客户端库。 我的终点

def post(self):
    data = api.payload
    u_token = data.pop('u_token')
    token = beaconapi.get_utoken()
    # other code ...

get_utoken 使用客户端的方法:

def get_utoken(self):
    ''' Checks if for beacon with given name u_token attachment
    is set.
    :param beacon_name: name of the beacon
    :param namespace: namespace
    '''
    beacon_name = self.get_default_auth_beacon_name()
    ctx = _app_ctx_stack.top # getting client from application context
    # ...
    response = ctx.proximitybeaconapi.beacons().attachments().list(**query)
    return response

但我得到了AttributeError: 'AppContext' object has no attribute 'proximitybeaconapi' 错误,尽管我之前在应用程序上下文中设置了这个属性:

  File "/home/devaerial/Source/automoticz-server/automoticz/utils/beacons.py", line 61, in get_default_auth_beacon_name
    response = ctx.proximitybeaconapi.beacons().list(q=query).execute()
AttributeError: 'AppContext' object has no attribute 'proximitybeaconapi'

当我在调用最后一个端点时使用init_api 设置proximitybeaconapi 客户端实例时,看起来ctx 上下文没有保存我的proximitybeaconapi 客户端实例

我在这里做错了什么?

P.S:我关注的是官方 Flask 文档中的 this 示例。

【问题讨论】:

    标签: python-3.x flask google-api-client flask-extensions


    【解决方案1】:

    在不使用_app_ctx_stack 的情况下找到了问题的解决方案。使用 this 方法使用 app.extensions 对象,其中 Flask 应用程序存储对扩展的所有引用并稍微重建我的代码:

    def init_api(self, credentials):
        ''' Initialize Proximity Beacon API
    
        :param credentials: google.oauth2.credentials.Credentials object  
        '''
        proximitybeaconapi = discovery.build(
               OAUTH2.API_NAME, OAUTH2.API_VERSION, credentials=credentials)
        self.app.extensions['api'] = proximitybeaconapi
    

    现在,如果我想调用 Goolge API 客户端,我只需从 extensions 获取它的引用

    def get_pin(self):
        ''' Checks if for beacon with given name pin attachment
        is set.
    
        :param beacon_name: name of the beacon
        :param namespace: namespace
        '''
        beacon_name = self.get_default_auth_beacon_name()
        api = self.app.extensions.get('api')
        namespace = self.get_default_project_namespace().split('/')[1]
        namespaced_type = '{}/pin'.format(namespace)
        query = {'beaconName': beacon_name, 'namespacedType': namespaced_type}
        resp = api.beacons().attachments().list(**query).execute()
        b64_data = resp['attachments'][0]['data']
        return self._base64_to_str(b64_data)
    

    【讨论】:

      猜你喜欢
      • 2014-12-17
      • 2021-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-04
      • 1970-01-01
      • 2012-07-11
      相关资源
      最近更新 更多