PythonでSharePointの特定サイトの特定リストの特定レコードのURLを取得する方法

# 本記事は
この記事の番外編になります。
[PowerApps でセンサーデータの値を取得してみた！（ソースもあるよ！）](https://qiita.com/rnakamuramartiny/items/e6acd2b2bed588290655)

# まず最初に・・・
## SharePointのレコードデータを取得するためにはどうするのか？
![image.png](https://qiita-image-store.s3.amazonaws.com/0/269159/a0d085a1-47c8-b4e0-51db-22fb8e587332.png)
このようなURL構造にして
メソッドによって処理を変えます。

* Get：レコードのデータを取得
* Patch：レコードを更新
* Delete：レコードを削除

## つまりは・・・
以下の手順を踏んでいけば、このURLパスが完成することになります。

1. サイト名を元に検索して、サイトIDを取得する
2. 取得したサイトIDからリスト名を元に検索してリストIDを取得する
3. 取得したサイトID及びリストIDから検索するレコードの特定カラムの文字列を検索してレコードIDを取得する

検索に必要なデータは予め変数として格納しておきます。

# では取得していきましょう。
## 検索用の変数
以下のようにします。

|変数名|用途|
|:--|:--|
|SPS_SiteName|検索するサイト名称|
|SPS_ListName|検索するリスト名称|
|SPS_SearchColumn|検索対象のリスト列名|
|SPS_SearchRecord|検索文言|

## サイトIDを取得する

```python:GetSPSSiteID

# サイトIDを取得するためのURLを生成する。
SiteGet_URL = 'https://graph.microsoft.com/v1.0/sites?search=' \
            + SPS_SiteName

# Microsoft Graphを実行し、その結果をres1に格納する。
res1 = requests.get(
                SiteGet_URL,
                headers=headers
            )
# requrest処理をクローズする
res1.close

# res1をjsonファイルに整形
res1json    = res1.json()

# 結果からSiteIDを取得する。
SiteID = res1json['value'][0]['id']
```

### res1jsonの取得結果

```json:res1json
{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites",
    "value": [
        {
            "createdDateTime": "2018-06-08T01:54:26Z",
            "id": "xxxxxxxx.sharepoint.com,xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx,xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",
            "lastModifiedDateTime": "2018-05-23T19:38:15Z",
            "name": "testsite",
            "webUrl": "https://xxxxxxxx.sharepoint.com/sites/zzzzzzzzzzzzzzzzzzzz",
            "displayName": "テストサイト",
            "root": {},
            "siteCollection": {
                "hostname": "xxxxxxxx.sharepoint.com"
            }
        }
    ]
}
```

### ここで詰まったところ
['value']['id']とすれば値が取得できると思っていました。
ところが、実際に投げたところ、こういうエラーが発生しました。

```
TypeError: string indices must be integers, not str
```

調べたところ、リストのインデックスは数値型じゃないとだめとのことです。
というわけで、値取得の方法を以下のように書き換えます。

```
SiteID = res1json['value'][0]['id']
```

今回、取得したjsonは1件しかない想定ですので
リストのインデックス番号「０」を付与することで
確実にパラメタを取得することができるようになります。

## リストIDを取得する

```python:GetSPSListID
# ListIDを取得するためのURLを生成する
ListGet_URL = "https://graph.microsoft.com/v1.0/sites/" + \
             SiteID + "/lists? + \
             $filter=displayName eq '" + SPS_ListName + "'"

# Microsoft Graphを実行し、その結果をres2に格納する。
res2 = requests.get(
                ListGet_URL,
                headers=headers
            )

# requrest処理をクローズする
res2.close

# res2をjsonファイルに整形
res2json    = res2.json()

# 結果からListIDを取得する
ListID = res2json['value'][0]['id']

```

### res2jsonの取得結果

```json:res2json
{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites('xxxxxxxx.sharepoint.com,xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx,xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx')/lists",
    "value": [
        {
            "@odata.etag": "\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx,13\"",
            "createdDateTime": "2019-02-13T12:51:59Z",
            "description": "",
            "eTag": "\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx,13\"",
            "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",
            "lastModifiedDateTime": "2019-02-14T13:16:31Z",
            "name": "IoT_Data",
            "webUrl": "https://https://xxxxxxxx.sharepoint.com/sites/zzzzzzzzzzzzzzzzzzzz/Lists/IoT_Data",
            "displayName": "IoT_Data",
            "createdBy": {
                "user": {
                    "email": "xxx@xxx.com",
                    "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",
                    "displayName": "テストユーザ"
                }
            },
            "lastModifiedBy": {
                "user": {
                    "email": "xxx@xxx.com",
                    "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",
                    "displayName": "テストユーザ"
                }
            },
            "parentReference": {},
            "list": {
                "contentTypesEnabled": true,
                "hidden": false,
                "template": "genericList"
            }
        }
    ]
}
```

### ここで詰まったところ
文字列をシングルクォート(')で囲っていたため
検索文字列をダブルクォート(")で囲うようにしてましたが
それだとエラーになったため
URL生成部分はダブルクォートにして以下のように宣言しました。

```
"https://graph.microsoft.com/v1.0/sites/" + \
             SiteID + "/lists? + \
             $filter=displayName eq '" + SPS_ListName + "'"
```

## レコードIDを取得する

```python:GetSPSRecordID
# RecoardIDを取得するためのURLを生成する
RecordGet_URL   = "https://graph.microsoft.com/v1.0/sites/" + \
                        SiteID + "/lists/" + ListID + \
                        "/items?expand= + \
                        fields(select=Id," + SPS_SearchColumn + \
                        ")&filter=fields/" + SPS_SearchColumn + " eq '" + \
                        SPS_SearchRecord + "'"

# Microsoft Graphを実行し、その結果をres3に格納する。
res3 = requests.get(
                RecordGet_URL,
                headers=headers
            )

# requrest処理をクローズする
res3.close

# res3をjsonファイルに整形
res3json   = res3.json()

# 結果からRecordIDを取得する
RecordID   = res3json['value'][0]['id']

```

### res3jsonの取得結果

```json:res3json
{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites('xxxxxxxx.sharepoint.com,xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx,xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx')/lists('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx')/items",
    "value": [
        {
            "@odata.etag": "\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx,48752\"",
            "createdDateTime": "2019-02-14T13:16:31Z",
            "eTag": "\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx\"",
            "id": "2",
            "lastModifiedDateTime": "2019-02-18T13:12:05Z",
            "webUrl": "https://https://xxxxxxxx.sharepoint.com/sites/zzzzzzzzzzzzzzzzzzzz/Lists/IoT_Data/2_.000",
            "createdBy": {
            	"user": {
                	"email": "xxx@xxx.com",
                	"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",
                	"displayName": "テストユーザ"
            	}
            },
            "lastModifiedBy": {
                "user": {
                    "displayName": "SharePoint アプリ"
                }
            },
            "parentReference": {},
            "contentType": {
                "id": "0x01003F9D3A2ADE72BA4BBEA8AB7FCD7ECD6D"
            },
            "fields@odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites('xxxxxxxx.sharepoint.com,xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx,xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx')/lists('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx')/items/$entity",
            "fields": {
                "@odata.etag": "\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx,48752\"",
                "Product": "PiSensor",
                "id": "2"
            }
        }
    ]
}
```

### ここで詰まったところ
検索クエリ部分ですね。
ここは試行錯誤するしかなかったです。
field で検索対象のリストからIDと検索対象のカラム名を指定し
filter関数で検索対象のカラム名のデータが何か？という指定をしています。


# まとめ
いかがだったでしょうか？
実運用で使用する場合は、やはりある程度変数化する必要があります。
今回、それを試していく中で、Microsoft Graph SharePoint の特性がちょっとわかった気がします。
みなさんのOffice365ライフで何かの足しになれば幸いです。