Code Overview

pgAdminの大部分は、バックエンドでFlaskフレームワークを使用して作成され、フロントエンドでCSS3、Bootstrap、jQueryを使用して作成された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リストの取得など。他の目的にも同じクラスを使用できます。そのクラスを継承し、メンバー変数operations、parent_ids、ids、node_typeをオーバーロードして、PgAdminModuleインスタンスにノードビューとして登録するだけです。

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

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

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モジュールのロードは、サーバーノードが完全にロードされた場合にのみ意味があります)。jsなどを使用して、コードをよりよく理解してください。