Code Overview

pgAdminの大部分は、バックエンドでFlaskフレームワークを使用して作成され、フロントエンドでCSS3、Bootstrap、およびjQueryを使用したHTML5を使用して作成されたPythonWebアプリケーションです。NWjs(NodeWebkit)を使用して作成されたWebアプリケーションよりもデスクトップアプリケーションを好むユーザー向けに、デスクトップランタイムも含まれています。

ランタイム

ランタイムは、ブラウザーとスタンドアロンアプリケーションを作成するPythonサーバーを統合するNWjsに基づいています。ソースコードは、ソースツリーの /runtime ディレクトリにあります。

ウェブアプリケーション

WebアプリケーションはpgAdminの大部分を形成し、ソースツリーの /web ディレクトリにあります。メインファイルは pgAdmin4.py で、組み込みのスタンドアロンWebサーバーの実行、または実稼働用のWSGIアプリケーションとして使用できます。

構成

コアアプリケーションの構成は config.py にあります。このファイルには、アプリケーションのすべての構成可能な設定と、それらの使用の説明が含まれています。Webサーバーに展開する前に、さまざまな設定を構成することが不可欠です。これらは config.py または config.py ( config.py ドキュメントを参照)でオーバーライドして、メイン構成ファイルの変更を回避できます。

ユーザー設定

デスクトップモードで実行している場合、pgAdminには、デスクトップユーザーに使用される単一のデフォルトのユーザーアカウントがあります。サーバーモードで実行している場合、アプリケーションを使用する前にログインする必要がある無制限のユーザーがいる場合があります。pgAdminは Flask-Security モジュールを利用してアプリケーションのセキュリティとユーザーを管理し、セルフサービスのパスワードリセットやパスワード変更などのオプションを提供します。

デスクトップモードでもサーバーモードでも、各ユーザーの設定はSQLiteまたはユーザーアカウントの保存にも使用される外部データベースに保存されます。これは、最初に setup.py スクリプトを使用して作成されます。その中にデータベースファイルとスキーマを作成し、最初のユーザーアカウント(管理権限を持つ)とデフォルトのサーバーグループを追加します。 setup.py テーブルは、ユーザー構成設定をキーと値の形式で保存するためにも使用されます。必須ではありませんが、設定キー(または名前)は通常、スラッシュを使用して人為的に名前空間の値にフォーマットされます。これは、LinuxまたはMacのpgAdmin3設定ファイルと同じです。

setup.py を実行する前にローカル構成をセットアップする必要があることに注意してください。ローカル構成は、特にデスクトップモードとサーバーモードに関して、スクリプトがデータベースを設定する方法を決定します。

pgAdminコア

pgAdminの心臓部は pgadmin パッケージです。これには、Jinjaエンジンで使用されるグローバルに利用可能なHTMLテンプレートと、マルチプルのモジュールで使用される画像、Javascript、CSSファイルなどのグローバルな静的ファイルが含まれています。

パッケージの作業は、そのコンストラクター __init__.py で処理されます。これは、ロギングと認証のセットアップ、他のモジュールの動的ロード、およびその他のいくつかのタスクを担当します。

モジュール

モジュールを追加することにより、機能のユニットがpgAdminに追加されます。これらはクラスのPythonオブジェクトインスタンスであり、 web/pgadmin/utils.py にあるPgAdminModuleクラス(Flaskブループリント実装)を継承します。他のモジュール(主にデフォルトモジュール-ブラウザー)が利用するさまざまなフックポイントを提供します。

モジュールとして認識されるには、Pythonパッケージを作成する必要があります。これは以下を行う必要があります。

  1. web/pgadmin/ ディレクトリ内に配置され、

  2. pgadmin.utils.PgAdminModuleクラスを実装します

  3. そのパッケージ内の特定のクラスを表すインスタンス変数(一般に blueprint という名前付け)。

各モジュールは、実装するブループリントの template および template ディレクトリを定義できます。名前の衝突を避けるために、テンプレートは、指定されたテンプレートディレクトリ内のディレクトリの下に、モジュール自分自身の名前を付けて保存する必要があります。たとえば、 template モジュールはそのテンプレートを template に保存します。これは、2番目のモジュール名を省略できる静的ファイルには適用されません。

ブループリントの定義に加えて、 views モジュールは通常、クライアント要求に応答してレンダリングされるすべてのビューを定義する責任があります。これらのビューにRESTAPIURLを提供する必要があります。これらには、適切なルートデコレータとセキュリティデコレータを含める必要があります。FlaskのMethodViewと同じアプローチを使用するNodeViewクラスを見てみましょう。 views にあります。この特定のクラスは、ブラウザーノードでさまざまな操作のRESTAPIURLを作成するために使用されます。つまり、リスト、作成、更新、削除、子の取得、統計/逆SQLの取得/そのノードの/dependencies/dependentsリストなど。他の目的にも同じクラスを使用できます。そのクラスを継承し、メンバー変数操作、parent_ids、ids、node_typeをオーバーロードして、PgAdminModuleインスタンスでノードビューとして登録するだけです。

ほとんどのpgAdminモジュールは、PgAdminModuleクラスが提供する hooks も実装します。これは、モジュールをアプリケーションの残りの部分に統合するためのフックポイントを提供する責任があります。。フックポイントが必要ない場合は、存在する必要はありません。それらを利用しようとする前に、それらが存在することを確認するのは呼び出し元の責任です。

現在実装されているフックは次のとおりです。

class MyModule(PgAdminModule):
    """
    This is class implements the pgadmin.utils.PgAdminModule, and
    implements the hooks
    """

    ...

    def get_own_stylesheets(self):
        """
        Returns:
            list: the stylesheets used by this module, not including any
                  stylesheet needed by the submodules.
        """
        return [url_for('static', 'css/mymodule.css')]

    def get_own_javascripts(self):
        """
        Returns:
            list of dict:
            - contains the name (representation for this javascript
              module), path (url for it without .js suffix), deps (array of
              dependents), exports window object by the javascript module,
              and when (would you like to load this javascript), etc
              information for this module, not including any script needed
              by submodules.
        """
        return [
            {
                'name': 'pgadmin.extension.mymodule',
                'path': url_for('static', filename='js/mymodule'),
                'exports': None,
                'when': 'server'
                }
            ]

    def get_own_menuitems(self):
        """
        Returns:
            dict: the menuitems for this module, not including
                  any needed from the submodules.
        """
        return {
            'help_items': [
                MenuItem(
                    name='mnu_mymodule_help',
                    priority=999,
                    # We need to create javascript, which registers itself
                    # as module
                    module="pgAdmin.MyModule",
                    callback='about_show',
                    icon='fa fa-info-circle',
                    label=gettext('About MyModule'
                    )
                ]
            }
    def get_panels(self):
        """
        Returns:
            list: a list of panel objects to add implemented in javascript
                  module
        """
        return []
    ...



blueprint = MyModule('mymodule', __name__, static_url_path='/static')

pgAdminモジュールには、必要に応じて、目的を達成するために必要な追加のPythonモジュールを含めることができます。また、他の動的にロードされるモジュールを参照することもできますが、定義されたフックポイントを使用し、特定のモジュールが存在しない場合に正常に失敗する必要があります。

ノード

ノードはモジュールに非常に似ており、個々のノードまたはオブジェクトエクスプローラーのツリービュー上のコレクションオブジェクトを表します。ノードモジュールとして認識されるには、Pythonパッケージ(JavaScriptモジュールとともに)を作成する必要があります。これは以下を行う必要があります。

  1. web/pgadmin/browser/ ディレクトリ内に配置され、

  2. BrowserPluginModuleを実装し、必要なRESTAPIを公開するノードビューを登録します

  3. クラスオブジェクトのインスタンス

フロントエンド

pgAdminは、フロントエンドの実装にJavaScriptを広く使用しています。require.jsを使用して遅延読み込み(または、必要な場合にのみ読み込む)を許可し、UIのルックアンドフィールにブートストラップとMaterialUIを、選択したノードのプロパティを生成/ダイアログを作成するReactを使用します。各モジュールを可能な限り小さな塊に分割しました。すべてのJavaScriptモジュールをロードする必要があるわけではありません(つまり、データベースにJavaScriptモジュールをロードすることは、サーバーノードが完全にロードされた場合にのみ意味があります。)JavaScriptファイルnode.js、browser.js、menu.js、panelをご覧ください。jsなどを使用して、コードをよりよく理解してください。