2

編集:

[MVC] タグと [design-patterns] タグを追加して、この質問の対象者を拡大しました。これは、Python や SQLalchemy に直接関係するものではなく、一般的なプログラミングの質問であるためです。これは、ビジネス ロジックと ORM を備えたすべてのアプリケーションに適用されます。
基本的な質問は、ビジネス ロジックを個別のモジュールに保持する方がよいか、ORM が提供するクラスに追加する方がよいかということです。

作業する構造をセットアップする必要があるフラスコ/sqlalchemy プロジェクトがあります。セットアップ方法については 2 つの有効な意見があり、プロジェクトが実際に開始される前に、そのうちの 1 つに決心したいと思います。彼ら。
2 つのうちどちらがより理にかなっているのか、その理由、および利点と欠点は何かについて、洞察を提供していただける方がいらっしゃいましたら、大歓迎です。


私の例は、一括して送信したり、1 人のユーザーに表示したりする必要がある HTML レターです。レターには、宛先のユーザー向けの請求書や記事のリストを表示するセクションを含めることができます。


方法 1:
コードを 3 つの層に分割します。1 層目: Web インターフェイス、2 層目: 文字の処理、3 層目: ORM (sqlalchemy) からのモデル。
Web サイトは、第 2 層のクラスでサーバー側メソッドを呼び出します。第 2 層は、このレターを取得する必要があるユーザーをループし、HTML を生成してレター内のいくつかの一般的なフィールドを置き換える内部メソッドを持ちます。現在のユーザーの情報。また、請求書またはレターに配置する記事のリストを生成する内部メソッドもあります。

この方法では、第 3 層はデータベースからデータを取得するためだけに使用され、ユーザーの名と姓から氏名を生成するなどのデータベース関連のロジックに使用される可能性があります。2 番目の層は、ほとんどの作業を実行します。

方法 2: コードを同じ 3 つの層に分割しますが、2 番目の層のユーザーのコレクションに対してのみループを実行します。

HTML、請求書、および記事のリストを生成するためのメソッドはすべて、ORM が提供する層 3 のモデル定義にメソッドとして追加されます。第 2 層はループを実行しますが、実際の機能は第 3 層のモデル クラスに含まれています。

どちらの方法も機能する可能性があり、どちらにも長所と短所があると結論付けました。

方法 1:

  • ビジネスロジックをデータベースアクセスから完全に分離
  • ORMモデルをインポートすると、必要のない多くのメソッド/機能もインポートされるのを防ぎ、モデルクラスのコードをよりコンパクトに保ちます。
  • テストのためにORMモデルをモックアウトするときに使いやすいかもしれません

方法 2:

  • DjangoがPythonで行う方法と一致しているようです
  • メソッドへの簡単なアクセスを許可します。モデル インスタンスが存在する場合、それが実行する関数をすぐに呼び出すことができます。(私の例では、letter-instance が利用可能な場合、そのレターの HTML を生成するメソッドを直接呼び出すことができます)
  • すべての適切なメソッドを手元に置いて、インスタンスを渡すことができます。
4

1 に答える 1

1

通常、この種のものにはMVCパターンを使用しますが、Python のほとんどの Web フレームワークは、不要なコンポーネントであると考えているため、"Controller" 部分を削除しています。私の発達において、これはある程度真実であることに気づきました:私はそれなしで生きることができます. これにより、ビューとモデルの 2 つのレイヤーが残ります。

問題は、ビジネスロジックをどこに置くかです。実際には、これを行うには 2 つの方法があります。少なくとも 2 つの方法で、ロジックを配置する場所に直面しています。

  • 複数のビューで必要になる可能性のあるロジックを処理する特別な内部ビュー メソッドを作成します。_process_list_data
  • モデルに関連しているが、対応するモデル モジュール内の単一のインスタンスに直接関連付けられていない関数を作成しますcheck_login

詳しく説明すると、最初のメソッドは厳密に表示関連のメソッドに使用します。つまり、表示目的でデータを処理することに関係しています。上記の例は、_process_list_data(メソッドを目的別にグループ化する) ビュー クラス内に存在しますが、モジュール内の通常の関数にすることもできます。データリストなどのいくつかのパラメーターを受け取り、それを何らかの方法でフォーマットします (たとえば、ビューパラメーターを追加して、テンプレートのロジックを減らすことができます)。次に、データセットを元のビュー関数に返します。元のビュー関数は、それを渡すか、さらに処理することができます。

2 番目のロジックは、テストを容易にするためにコードを直接表示しないようにしたい他のほとんどのロジックに使用されます。私の例check_loginはこれを行います:これは、ユーザーのログイン資格情報を確認し、ユーザーを返すかログイン失敗を報告するかを決定することであるため、表示出力に直接結び付けられていない関数です(例外をスローすることにより、 returnFalseまたはreturn None) . ただし、この機能はモデルにも直接関連付けられていないため、ORM クラス内に存在することはできません (オブジェクトstaticmethodの場合もありUserます)。代わりに、モジュール内の単なる関数です (覚えておいてください、これは Python です。利用可能な最も単純なアプローチを使用する必要があり、関数は何かのために存在します)。

これを要約すると、ほとんどのロジックは何らかの形で特定のモデルに関連付けられているため、ビューにロジックを表示し、モデル内の他のすべてのものを表示します。そうでない場合は、この種のロジック専用の新しいモジュールまたはパッケージを作成します。これは、個別のモジュールまたはパッケージである可能性があります。たとえば、utilビュー、モデルなどに直接関連付けられていないヘルパー関数のモジュール/パッケージを作成することがよくあります。テンプレート内で定義されています。

ここで、このロジックをタスクに取り入れます: 文字の処理/作成。どのような処理を行う必要があるのか​​ 正確にはわからないため、私の仮定に基づいた一般的な推奨事項しか提供できません。

いくつかのデータがあり、それを手紙に取り入れたいとしましょう。たとえば、これらの記事を購入しarticlesた人のリストがあります。costumerその場合、すでにデータを持っています。テンプレートに渡す前に行う必要がある唯一のことは、テンプレートが簡単に使用できるように再フォーマットすることです。例えば、購入した物品を、例えば量、価格、または物品番号によって注文することが望まれる場合がある。これはモデルから独立したものであり、順序は表示関連のみになりました (データベース クエリで順序を指定することもできますが、指定しなかったと仮定しましょう)。この場合、これはビューが実行する操作であるため、テンプレートには表示できるようにフォーマットされたデータが含まれています。

ここで、特定のレターを作成するためのデータを取得したいとします。たとえば、ユーザーが経時的に購入した記事のリストと、それらが購入された日付やその他の詳細です。これはモデルの仕事です。たとえば、クエリを作成し、データを取得し、この特定のタスクに必要なすべてのプロパティが含まれていることを確認します。

どちらの場合も、製品の価格を取得する必要があり、その価格は基本値と他のプロパティに基づくいくつかのパーセンテージによって決定されるとします。これは、単一の製品または注文インスタンスで動作するため、モデルメソッドとして理にかなっています。 . 次に、モデルをテンプレートに渡し、その中で price メソッドを呼び出します。ただし、呼び出しが既にビューで行われ、テンプレートがタプルまたはディクショナリのみを取得するように、再フォーマットすることもできます。これにより、同じデータを API として簡単に渡すことができます (以下を参照) が、必ずしも最も簡単で最良の方法であるとは限りません。

この決定の良いルールは、自分の標準ビューに追加で JSON API を提供する場合、できるだけ DRY になるようにコードをどのように変更する必要があるかを自問することです。. 最初に理論だけでは不十分な場合は、テンプレート用のいくつかの API を作成し、ビュー自体の横にある API に変更する必要がある場所を確認してください。この API は決して使用しない可能性があるため、完璧である必要はありませんが、コードを構造化する方法を理解するのに役立ちます。ただし、上記で見たように、必ずしも JSON に変換できるものだけを返すようにデータの前処理を行う必要があるというわけではありません。代わりに、API 用に JSON 固有のフォーマットを作成する必要がある場合があります。見る。

そのため、意図したよりも少し長くなりましたが、いくつかの例を提供したいと思いました。なぜなら、私が始めたときに見逃していたものであり、試行錯誤を経てそれらのことを見つけたからです.

于 2013-09-20T10:29:53.140 に答える