带有python和html的Microsoft Graph API Paging接口

时间:2018-08-06 20:50:44

标签: python html flask pagination microsoft-graph

当前,我正在尝试使用@ odata.nextLink对我从图形API检索的数据进行分页。我将需要在html上来回移动一些箭头,因此我可能不得不在python代码上使用flask创建一些函数,以使用json文件中的@ odata.nextLink值,因此它将加载下一组数据的。我一直想做的事情是这样的,但是我的“下一步”功能将只检索第二组数据,它缺少返回的功能,并且我创建了第二个html文件来显示下一个数据块,是没有意义的。我希望你们能给我一个关于如何工作的想法。

Python代码:

import base64
import mimetypes
import os
import pprint
import uuid

import flask
from flask_oauthlib.client import OAuth
from flask import request

import config

APP = flask.Flask(__name__, template_folder='static/templates')
APP.debug = True
APP.secret_key = 'development'
OAUTH = OAuth(APP)
MSGRAPH = OAUTH.remote_app(
    'microsoft',
    consumer_key=config.CLIENT_ID,
    consumer_secret=config.CLIENT_SECRET,
    request_token_params={'scope': config.SCOPES},
    base_url=config.RESOURCE + config.API_VERSION + '/',
    request_token_url=None,
    access_token_method='POST',
    access_token_url=config.AUTHORITY_URL + config.TOKEN_ENDPOINT,
    authorize_url=config.AUTHORITY_URL + config.AUTH_ENDPOINT)

@APP.route('/')
def homepage():
    """Render the home page."""
    return flask.render_template('homepage.html')

@APP.route('/login')
def login():
    """Prompt user to authenticate."""
    flask.session['state'] = str(uuid.uuid4())
    print(config.REDIRECT_URI)
    return MSGRAPH.authorize(callback=config.REDIRECT_URI, state=flask.session['state'])

@APP.route('/login/authorized')
def authorized():
    """Handler for the application's Redirect Uri."""
    if str(flask.session['state']) != str(flask.request.args['state']):
        raise Exception('state returned to redirect URL does not match!')
    response = MSGRAPH.authorized_response()
    flask.session['access_token'] = response['access_token']
    print(flask.session['access_token'])
    return  flask.redirect('/query')



@MSGRAPH.tokengetter
def get_token():
    """Called by flask_oauthlib.client to retrieve current access token."""
    return (flask.session.get('access_token'), '')

def request_headers(headers=None):
    """Return dictionary of default HTTP headers for Graph API calls.
    Optional argument is other headers to merge/override defaults."""
    default_headers = {'SdkVersion': 'sample-python-flask',
                       'x-client-SKU': 'sample-python-flask',
                       'client-request-id': str(uuid.uuid4()),
                       'return-client-request-id': 'true'}
    if headers:
        default_headers.update(headers)
    return default_headers


@APP.route('/query')
def query():
    # query = "groups?$filter=startswith(displayName,'C')"
    query = "groups/?$expand=members"

    result = MSGRAPH.get(query, headers=request_headers()).data

    return flask.render_template('query.html',result=result, query=query)

@APP.route('/next')
def next():

    query = "groups/?$expand=members"
    result = MSGRAPH.get(query, headers=request_headers()).data
    nextResult = MSGRAPH.get(result['@odata.nextLink'], headers=request_headers()).data

    return flask.render_template('query_2.html', result=nextResult, query=query)
# Last Group Was: APP_EZSHARE_CO-O0004

if __name__ == '__main__':
    APP.run()

HTML文件:

<!DOCTYPE html>
<!-- Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
See LICENSE in the source repository root for complete license information. -->
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>{{ sample }} sample</title>
        <link rel="stylesheet" type="text/css" href="/static/css/bootstrap.min.css" />
        <link rel="stylesheet" type="text/css" href="/static/css/site.css?version=1.28" />
    </head>
    <body>
        <div class="container homepage-container">
            <div>
                <h1 style="text-align: center">Active Directory Viewer</h1>




                <div>
                    <!--<h1>Result</h1>-->
                    <table border="1px solid black">
                    <tr>
                        <!--<th>ID</th>-->
                        <th>Group Name</th>
                        <th>Description</th>
                        <!--<th>Users</th>-->
                    </tr>

                    {% for gd in result.value %}
                    <tr style="background-color: green; color: white">
                        <!--<td>{{ gd.id }}</td>-->
                        <td>{{ gd.displayName }}</td><!-- TRYING TO ACCESS THE GROUP DISPLAYNAME-->
                        <td>{{ gd.description }}</td>
                    </tr>

                    {% for mem in gd.members %}
                    <tr>
                        <td>{{ mem.displayName }}</td>
                    </tr>
                    {% endfor %}

                    {% endfor %}
                    </table>

                    <a href="/next"><input type="button" value="Next"></a>
                    <!--{{ result }}-->
                </div>



            </div>
        </div>
    </body>
</html>

谢谢!

1 个答案:

答案 0 :(得分:0)

正如您所引用的那样,由于Microsoft Graph API的分页机制不提供双向分页,因此我不会使用它为用户提供这种功能。相反,我将使用$skip参数。确实,如该文章所述:

  

某些Microsoft Graph API(例如Outlook Mail和日历(消息,事件和日历))使用$skip来实现分页。

对于某些Graph API的@odata.nextLink值中使用的$skipToken参数的持久性,我也找不到Microsoft的任何保证,因此,请谨慎使用用户面向上下文的情况下,它可能很快过期(在该API的当前主要版本的当前版本或未来版本中)。

如果仅使用$skip参数提供分页,则结果JSON的格式将相同,因此您应该能够为第一页和所有后续页面使用相同的HTML模板。我只有一条/query路由(而不是/next路由),它只接受一个名为skip之类的可选参数。