このサイトについて

みんなのPython Webアプリ編 - O/Rマッパーを使ったデータベースの操作

みんなのPython Webアプリ編 - O/Rマッパーを使ったデータベースの操作

O/Rマッパーを使ったデータベースの操作

テンプレートエンジンを使うことによって、WebアプリケーションのプログラムからHTMLを完全に追い出すことができました。結果として、プログラムがスッキリし、見通しがよくなりました。

そもそもプログラムとは、データを処理し、結果を返す、という手続きを記述するためにあるものです。Webアプリケーションであれば、データを受け取って加工したり、必要に応じてデータベースなどに保存する、または保存したデータをデータベースから取り出して処理をする、というようなことが主な処理の内容になります。

そのような処理の中に、HTMLのようなプログラムとは異質な文字列が紛れ込んでいると、結果としてプログラムの見通しが悪くなってしまいます。Webアプリケーションの出力となるHTMLを組み立てる処理はたいてい単調で冗長です。HTMLのような異質な文字列だけでなく、本質的でない処理がプログラムに紛れ込むことも、プログラムの見通しを悪くする原因となります。

HTMLと同様に、データベースとの通信を行うときに利用するSQLもまた、Webアプリケーションのプログラムに紛れ込む異質な文字列と言えるかもしれません。データベースの操作も、HTMLを文字列として組み立てる作業と似て、単調な文字列処理の繰り返しになりがちです。SQLをWebアプリケーションのプログラムから追い出すことができれば、プログラムはもう少しスッキリするはずです。

テーブルとクラスの関係

実際に、SQLをプログラムから追い出す方法について考える前に、データベースについてもう少し考察を深めてみましょう。

データベースでは、データを表のような形式にして保存します。表には、保存したいデータの種類の数だけカラムを作ります。どのような表を作るかを定義するのがテーブルです。データベースにデータを保存するためには、まずテーブルを作る必要があります。テーブルは、いわば保存するデータの型の定義に相当します。

データベースに保存するデータは、テーブルに定義されたデータの型に応じた形式で保存します。テーブルをひな形としてデータの型を決めて、データを保存していくわけです。

このテーブルとデータの関係は、ちょうどPythonのようなオブジェクト指向言語のクラスとインスタンスオブジェクトの関係に似ています。クラスには型を定義しますので、テーブルに似た性質を持っています。クラスインスタンスはクラスという型をひな形にして作りますので、データベース上のデータ(列)に似た性質を持っていると言えます。

テーブルとクラスの違い

テーブルとクラス、データとインスタンスオブジェクトは似た面がある半面、異なった性格も持っています。

たとえば、データベースのテーブルは単に入れ物の形を定義しているにすぎません。データベースから取り出したデータも単なる値です。入れ物からデータを取り出したり追加をするためには、SQLという特殊な文法を持った文字列を組み立てる必要があります。

データと、データを操作するための手続きが明確に分かれているのがデータベースの特徴といえます。

一方、Pythonのクラスは単なる入れ物ではありません。また、インスタンスオブジェクトもただのデータではありません。クラスもインスタンスも、定義されているデータに関する処理を実行することができます。Pythonの場合は、インスタンスオブジェクトやクラス自体を対象にメソッドという形式で処理を実行します。たとえばPythonのリスト型では、リストの反転、ソート順の変更など、データを処理するときに便利なメソッドがたくさん用意されています。

データと手続きが一体になっているのが、クラスやインスタンスオブジェクトの流儀です。

データベースとクラスの違いについて簡単に見たことろで、次にいくつかの典型的な処理を例にとってみましょう。データベースとクラスの間で、処理方法がどのように違うかを具体的に比較したいと思います。

データを登録する場合

データベースの場合は、INSERT文というSQLの文字列を作ってデータベースに送信することでデータを登録します。登録したいデータは、数値であっても文字列に変換してSQLに埋め込みます。SQLは以下のようになります。大文字で書いてあるのはSQLのうち定型の部分です。小文字で書いてある文字はカラム名を指定したり、データを指定する部分で、状況によって変化します。

:::sql
INSERT INTO testtable(row1, row2) VALUES(1, 'foo')

Pythonのクラスの場合は、クラス自体を関数のように呼び出してインスタンスオブジェクトを作ります。登録したいデータは、引数の形で渡すことがほとんどです。数値、文字列など、登録したいオブジェクトをそのまま渡すことができます。

SQL文字列を組み立て、登録したいデータを文字列に変換する必要があるなど、データベースの操作の方が多少面倒なようです。ただし、どちらの処理も似通っていて、どちらが取り立てて大変、というわけではなさそうです。インスタンスを生成するコードは以下のようになります。

:::python
ins=TestClass(att1=1, att2='foo')

特定のデータを更新する場合

データベースの場合は、UPDATE文というSQL文字列を組み立てる必要があります。SQLには、更新したいデータのカラム名とデータそのものの他に、更新したいデータを特定するための情報を記載する必要があります。IDのような特別な情報を使って、更新する対象となるデータを指定する必要があるわけです。SQL文字列の書き方が面倒ですし、コードを見てもなにを実行しようとしているのか分かりづらくなってしまうかも知れません。

:::sql
UPDATE testtable SET row1=2, row2='bar' WHERE id=1

Pythonクラスの場合は、インスタンスのアトリビュートにデータを保存することがほとんどです。アトリビュートのデータを更新するためには、イコールを使ってアトリビュートに代入を行うか、アクセサと呼ばれるメソッドを呼び出します。データそのものに対して操作が行えるため、コードの書き方も簡単になりますし、処理の内容を直感的に把握しやすくなるはずです。

:::python
ins.row1=2
ins.row2='bar'

データの更新という点でみると、データベースよりクラスを使った処理の方が簡潔に実行できることが分かります。簡潔に実行できる処理は、コードも短くて済みますし、短いコードであれば処理の内容も把握しやすくなるはずです。

また、データベースの場合は、更新の処理をSQLという文字列に埋め込まなければなりません。そのため、Pythonのコードに比べて処理の実現方法が大きく異なっているのがよく分かります。

このように、データを扱う処理の一部では、クラスやインスタンスオブジェクトの方がより短く、分かりやすく処理を実行できるのです。 テーブルとクラス、データとインスタンスオブジェクトは互いによく似た関係にあります。もし、データベース上のクラスをクラスとして、データをインスタンスオブジェクトとして表現できたら、とても便利なはずです。

まず、SQLをPythonのプログラムから追い出すことができます。その上、データベースの処理を純粋なPythonのプログラムとして書けるようになります。SQLのようにPythonのプログラムと違った異質なものを追い出して、より純粋なPythonのコードだけをプログラムに書けるようになれば、より見通しがよいプログラムになるはずです。

O/Rマッパーとは

すでに解説してきたとおり、データベースでデータを扱う手法と、Pythonのようなオブジェクト指向的なデータの扱い方の間には大きなギャップがあります。データベースでは、データとデータを操作するための手続きが完全に分離しています。対してオブジェクト指向言語では、データと手続きが一体になっています。データを扱うときの考え方がそもそも異なるので、プログラムの中でデータベースを扱うときには、非Pythonな方法でデータを扱う必要が出てきます。

Webアプリケーションに限らず、データの操作を行う処理は、プログラムの基本部分といってよいくらい重要な部分です。そのような重要な部分に、非Python的な手法を使わなければならないとすると、プログラムは手軽に書けなくなってしまいます。インスタンスの生成、アトリビュートへの代入やメソッド呼び出しなど、Python的な手法を使ってデータベースを操作できれば、もっと手軽に、かつ簡潔にプログラムが書けるようになるはずです。

O/Rマッパーは、データベースとオブジェクト指向言語の間にあるギャップを埋める役割でよく利用される仕組みです。「O」は「オブジェクト」、「R」は「リレーショナル」を意味します。オブジェクト指向言語で利用されるオブジェクトと、リレーショナルデータベースのデータをうまくマッピングし、間を取り持ってくれる仕組みのことを指します。

O/Rマッパーにはたくさんの種類があり、マッピングの手法もいろいろとあります。O/Rマッパー全体に共通しているのは、データベース上のデータをオブジェクトとして扱えるという特徴です。データを取り出したり、データを更新するために、SQL文字列を作る必要がほとんどありません。数値や文字列など、ごく普通のデータと同じように、データベース上のデータを扱えるのです。

O/Rマッパーを使っても、データベースと通信をするためにはどこかで誰かがSQL文字列を作る必要があります。データベースとの実際の通信は、O/Rマッパーが裏側で密かに実行しています。O/Rマッパー自体に、便利なメソッドが定義してあったり、演算子のオーパーライドといった手法を活用して、SQL文字列を組み立て、適切にデータベースと交信を行うような作りになっているわけです。

図01 O/Rマッパーの働き

図01 O/Rマッパーの働き

2014-09-03 15:00