tkherox blog

データサイエンスおよびソフトウェア開発、たまに育児についての話を書いています

DjangoのORMにおけるコネクション管理

事の経緯

DjangoのORMについて深く理解しておらず,Djangoにおけるコネクションの管理とかってどうなっているのだろと気になったので調べてみました.
加えて,このままなんとなくで利用していたら,いつか絶対バグを生み出しかねないと不安になったのも調べたいと思った1つの要因です.

本記事は自身の備忘録としてまとめようと思います.
そのため,詳細な解説等は省いてしまう部分もあるかと思いますが,Djangoのデータベースに関する記事って意外と少なくて探すのに苦労するので,少しでも他の方の参考になれば幸いです. (公式ドキュメント読めって話ですが...)

Django ORMとは

Djangoではデータベースの操作をORMと呼ばれるデータベースとプログラムミング言語間のオブジェクトを変換するプログラミング技法が使われております.利用者はこのORMを介してデータベースを操作することで効率的な開発やセキュアプログラミングを実現することができます.
例えば,以下のようなモデルを定義していた場合を想定してみましょう.

from django.db import models

class Post(models.Model):
    author = name=CharField(max_length=255) 
    title = models.CharField(max_length=200)
    text = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

このモデルに対してORMを利用することでSQLを意識することなくデータベースの情報を取得してオブジェクトとして扱うことが可能になります.

from django.http import HttpResponse
from .models import Post

def index(request):
    post = Post.objects.all()  # データベースにあるPostを全て取得
    return HttpResponse(post)

非常に便利な機能ですよね.
ORMを利用することでMigration等も実施できるため類似機能としてSQLAlchemyやStormといった別のツールがありますが,Djangoを利用するのであればDjango ORMを利用した方が良いかと思います.

Connection管理

さて,本題のDjangoのORMにおけるコネクションの管理についてです. DjangoのORMでコネクションを接続するタイミングはいつなのでしょうか.

答えはリクエストを受けてから 初めてSQLが発行されるタイミング の時です.
以下で説明するとHTTPリクエストを受けてルーティングによってupdateメソッドが呼び出された時の1回目のPost.objects.get(id=id)を実行したタイミングでデータベースのコネクション接続が行われます.以降は初回に接続したコネクションを利用してSQLを実行するため,2回目のPost.objects.get(id=id)ではコネクション接続はせずにSQLを実行しています.

from django.http import HttpResponse
from .models import Post

def index(request):
    posts = Post.objects.all()  # データベースにあるPostを全て取得
    return HttpResponse(posts)

def update(request, id):
    # 1回目の変更
    post = Post.objects.get(id=id)
    post.title = 'first change!'
    post.save()
    # 2回目の変更
    post = Post.objects.get(id=id)
    post.text = "second change!"
    post.save()

    return HttpResponse(post)

ここで,ごく稀にDBのコネクション接続をSQL毎に実施したいという要望があるかと思います.その場合は以下のように実装して強制的にコネクションをクローズするように実装します.

from django.db import connection
from django.http import HttpResponse
from .models import Post

def update(request, id):
    # 1回目の変更
    post = Post.objects.get(id=id)
    post.title = 'first change!'
    post.save()
    connection.close()    # コネクションのクローズ

    # 2回目の変更
    post = Post.objects.get(id=id)
    post.text = "second change!"
    post.save()

    return HttpResponse(post)

ただし,これはリソースの観点からは推奨されません.
というのもデータベースへの接続を再確立することになるため接続のオーバーヘッドが増加することになります.リクエストで接続を開始してからコネクションを継続するのはこのオーバーヘッドを回避するための仕様になります.そのため,必要がない限りはコネクションを開始してからはリクエストが終了するまで継続して利用するようにしましょう.

まとめ

今回はDjangoのコネクションに関する内容を記載しました.
CONN_MAX_AGEConnection Poolなど他にも残しておきたい備忘録は多々ありますが,今回はコネクション管理のみについて簡単にまとめておきました. また,別の機会にDjango ORMに関する情報は継続的に記載していこうと思います.