Django 3.1のAsync Views

Django3.1が2020年8月にリリースされ、Async Viewsをサポートするようになりました。つまりView関数に加えて、Viewコルーチンを使えるのです。

今回は以下の過去記事のサンプルを、Viewコルーチンとして実装してみたいと思います。
[Python Asyncio入門 - Qiita](https://qiita.com/sand/items/0e445a13d81d20ea33c3)


まずは、Pythonの仮想環境に、必要なライブラリをインストールして、Djangoプロジェクトを作成します。

```
python3.8 -m venv venv
venv\Scripts\activate
pip install aiohttp
pip install bs4       # BeautifulSoup
pip install django
django-admin startproject hello_async 
cd hello_async
```

viewsを以下のようにコーディングします。
indexはasyncをつけていますが（つまりコルーチン）、ボディにawait行がないので、なくても同じです。
async_viewはコルーチンです。await asyncio.gather()行で、3サイトのスクレイピングを、コンカレントに実行しています。3サイトでのすべての実行が終わるまでawaitします。


```python:hello_async/views.py
import asyncio
import aiohttp
import datetime
from django.http import HttpResponse
from bs4 import BeautifulSoup

# helpers

async def one_site(session, url, title):
        today = datetime.date.today().strftime('%Y/%m/%d')
        out = "-"*15 + f'{title} ({today})' + "-"*15 + "\n"
        async with session.get(url) as resp:
            data = await resp.text()
            soup = BeautifulSoup(data, "lxml")
            for i, el in enumerate(soup.find_all("li", class_="zg-item-immersion")):
                name  = el.find_all("div", class_="p13n-sc-truncate")[0].string.strip()
                price = el.find("span", class_="p13n-sc-price") # .string.strip()
                price = price.string.strip() if price is not None else "???"
                out = out + f"[{i+1}] {name} ({price})\n"
        return(out)

# views

async def index(request):
    return HttpResponse("ハロー, async Django!...3.1")


async def async_view(request):
    async with aiohttp.ClientSession() as session:
        sites = [("https://www.amazon.co.jp/gp/top-sellers/books/ref=crw_ratp_ts_books", '本の売れ筋ランキング'),
                 ("https://www.amazon.co.jp/gp/bestsellers/books/466298/ref=zg_bs_nav_b_1_b", 'コンピュータ・ITの売れ筋ランキング' ),
                 ("https://www.amazon.co.jp/gp/bestsellers/books/492352/ref=zg_bs_nav_b_2_466298", 'プログラミングの売れ筋ランキング')]
        tasks = [asyncio.create_task(one_site(session, *site)) for site in sites]
        # tasks = [one_site(session, *site) for site in sites]
        outs = await asyncio.gather(*tasks)
        for out in outs:
            print(out)

    return HttpResponse("ノンブロッキング HTTP request!!!")
```

urlpatterns を以下のように定義します。


```python:hello_async/urls.py
from django.contrib import admin
from django.urls import path

from hello_async.views import index, async_view


urlpatterns = [
    path("async/", async_view),
    path("", index),
]
```

Async viewの実行には**ASGI**サーバが必要ですので、ここでは**uvicorn** を利用することにします。以下のコマンドでuvicornをインストールし、起動します。

```
# python manage.py runserver    # 通常のWSGIサーバは使わない
pip install uvicorn             # ASGIサーバ uvicorn をインストール   
uvicorn hello_async.asgi:application   # uvicorn を起動する
```

ブラウザで以下のサイトにアクセスすると、アプリが起動します。

```
http://127.0.0.1:8000/async/
```

コマンドラインに、以下のスクレイピング結果を表示した後に、ブラウザのレスポンスが返り「ノンブロッキング HTTP request!!!」と表示されます。

```
---------------本の売れ筋ランキング (2021/02/12)---------------
[1] 滝沢眞規子が本当に欲しかった LUNCH BOX BOOK (宝島社ブランドブック) (￥2,530)
[2] 映画ノベライズ 天外者 (￥1,485)
[3] 人新世の「資本論」 (集英社新書) (￥1,122)
[4] 本当の自由を手に入れる お金の大学 (￥1,540)
[5] スマホ脳 (新潮新書) (￥1,078)
[6] あきない世傳 金と銀(十) 合流篇 (ハルキ文庫 た 19-25 時代小説文庫) (￥682)
[7] 1日1話、読めば心が熱くなる365人の仕事の教科書 (￥2,585)
[8] パンダ自身 (光文社女性ブックス VOL. 185 女性自身MOOK) (￥1,200)
[9] 推し、燃ゆ (￥1,540)
[10] 日本のいちばん長い日 決定版 (文春文庫) (￥770)
---
[50] スパイダーゲドン 3冊ボックスセット (￥8,800)

---------------コンピュータ・ITの売れ筋ランキング (2021/02/12)---------------
[1] iPadはかどる! 仕事技2021(全iPad・iPadOS 14対応/リモートワークにも最適な仕事技が満載) (￥1,320)
[2] スマホ脳 (新潮新書) (￥1,078)
[3] いちばんやさしいアジャイル開発の教本　人気講師が教えるDXを支える開発手法 「いちばんやさしい教本」シリーズ (￥880)
[4] プログラミング超初心者が初心者になるためのPython入門（１）　セットアップ・文字列・数値編 (￥250)
[5] 2040年の未来予測 (￥1,870)
[6] iPad仕事術！SPECIAL 2020（手書きノート大特集! !） (￥990)
[7] iPad便利すぎる！280のテクニック（iPadOS 14対応・最新版!） (￥990)
[8] #ズボラPhotoshop 知識いらずの絶品3分デザイン (￥1,089)
[9] できる イラストで学ぶ 入社1年目からのExcel VBA できる イラストで学ぶシリーズ (￥979)
[10] スラスラ読める JavaScriptふりがなプログラミング (￥913)
---
[50] 関数は「使える順」に極めよう！ Excel 最高の学び方 できるビジネスシリーズ (￥693)

---------------プログラミングの売れ筋ランキング (2021/02/12)---------------
[1] プログラミング超初心者が初心者になるためのPython入門（１）　セットアップ・文字列・数値編 (￥250)
[2] 【Amazon.co.jp 限定】 1冊ですべて身につくHTML & CSSとWebデザイン入門講座 (DL特典: CSS Flexbox チートシート) (￥2,486)
[3] ゼロからのOS自作入門 (￥4,180)
[4] まいぜんシスターズとマイクラを遊ぼう! (扶桑社ムック) (￥1,100)
[5] C#を勉強する順番: 文法プログラマーを卒業する方法 (￥99)
[6] JavaScriptエンジニアのためのNode.js入門 (￥350)
[7] リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice) (￥2,640)
[8] スクラム実践者が知るべき97のこと (￥2,640)
[9] ゼロからFlaskがよくわかる本: Pythonで作るWebアプリケーション開発入門 (￥630)
[10] ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装 (￥3,740)
---
[50] 速習 Python 3 中: オブジェクト指向編 (￥800)

INFO:     127.0.0.1:54830 - "GET /async/ HTTP/1.1" 200 OK
```


今回は以上になります。