大きくなりすぎた models.py の対処方法について

例えばある Product という「ひとつ」のモデルに対する処理が大きくなりすぎた場合の対処の仕方について考えてみたいと思います。

参考にした神様サイト
Separation of business logic and data access in django


解1. models.py ファイルを分割する。

これが1番シンプルで、いいと思います。
Djangoのアプリケーションでmodelsモジュールを複数ファイルに分割する - 偏った言語信者の垂れ流し

利点
1) 通常の models.py の素直な拡張で理解しやすい。

欠点
1) モデルの定義が分散してしまうため、モデルの構造を若干おいずらくなる。
 

解2. ラッパークラスを作る。

# domains/product.py

class ProductDomain():
  
  product = None
  
  def __init__(product):
    self.product = product
  
  def method1():
    ...

  def method2():
    ...

利点
1) ファイルを分割して明確にデータの定義と処理の定義を分けられる。

欠点
1) 呼び出しの記述が冗長になる。

p  = Product.objects.get(name="egg")
pd = ProductDomain(p)

2) ラッパークラスで関数を定義するときの変数の呼び出しが面倒になる。
 

解3. プロキシモデルを使う。

プロキシモデル
# models.py

class Product(models.Model):

    field1 = ...
    field2 = ...

 

# proxy_models/product.py

class ProductDomain(Product):
    
    class Meta:
        proxy = True

    def method1():
      ...

    def method2():
      ...

 

利点
1) ファイルを分割して明確にデータの定義と処理の定義を分けられる。

欠点
1) 直接モデルが呼べない。

# NG
p = Product.objects.get(name="egg")
# OK
p = ProductDomain.objects.get(name="egg")

2) マルチテーブル継承がしづらくなる。
例えば Product モデルを継承した Cake モデルを作る際には、Product モデルではなく ProductDomain クラスを継承しなければならなくなります。

Product --- ProductDomain
             | 
            Cake ------------ CakeDomain

何故なら Cake モデルが Product モデルを継承してしまった場合、CakeDomain クラスを作る際に、ProductDomain クラスと Ckae モデルを多重継承することになります。すると、菱形継承になってしまうため、あまり好ましくありません。

Product --- ProductDomain --
 |                         |
 |--------- Cake ------------ CakeDomain

 


 

複数のモデルを扱う処理について

2つ以上のモデルの処理を扱う場合は、ラッパークラスを作る方法がいいのかなと思います。理由は、多重継承を心配する必要がないからです。あと、Stackoverflow のサイトだと、個々の変数に対して、処理を定義してたけど、それよりも、こんな感じで組み込んでしまったほうが、クライアント側のプログラムは楽だと思うので。
 

class TradeDomain():
  
  product = None
  person = None
  
  def __init__(product, person):
    self.product = product
    self.person = person
  
  def method1():
    ...

  def method2():
    ...