2009-08-11 57 views
4

我有一個關於Django的設計問題。我不太清楚如何應用鬆耦合應用程序的原則,以解決這個特定問題:應用程序和模型繼承的鬆耦合

我有一個訂單應用程序,管理訂單(在網上商店)。在此訂單應用程序我有兩類:

class Order(models.Model): 
    # some fields 
    def order_payment_complete(self): 
     # do something when payment complete, ie. ship products 
     pass 

class Payment(models.Model): 
    order = models.ForeignKey(Order) 
    # some more fields  
    def save(self): 
     # determine if payment has been updated to status 'PAID' 
     if is_paid: 
      self.order.order_payment_complete() 
     super(Payment, self).save() 

現在實際的問題:我有這樣的擴展了這個順序更專業的應用程序。因此,它增加了一些更多的領域吧,等等。例如:

class SpecializedOrder(Order): 
    # some more fields 
    def order_payment_complete(self): 
     # here we do some specific stuff 
     pass 

當然現在的預期行爲將是如下:我創建了一個SpecializedOrder,此訂單的付款放置和SpecializedOrder的order_payment_complete()方法叫做。但是,由於付款與訂單鏈接,而非專業訂單鏈接,因此將調用基本訂單的order_payment_complete()方法。

我真的不知道實現這種設計的最佳方式。也許我完全沒有 - 但我想構建這個訂單應用程序,以便我可以將其用於多種目的,並希望保持它儘可能通用。

如果有人能幫助我在這裏,這將是偉大的! 謝謝, Nino

回答

4

我認爲你在尋找什麼是從CONTENTTYPES框架,它隨Django中的GenericForeignKey在contrib包中。它處理記錄子類實例的類型和ID,並提供一種無縫訪問子類作爲模型外鍵屬性的方法。

在你的情況下,它會是這個樣子:

from django.db import models 
from django.contrib.contenttypes.models import ContentType 
from django.contrib.contenttypes import generic 

class Payment(models.Model): 

    order_content_type = models.ForeignKey(ContentType) 
    order_object_id = models.PositiveIntegerField() 
    order = generic.GenericForeignKey('order_content_type', 'order_object_id') 

你不需要做任何特殊才能使用此外鍵...泛型負責設置和透明地保存order_content_typeorder_object_id領域:

s = SpecializedOrder() 
p = Payment() 
p.order = s 
p.save() 

現在,當你Payment保存方法運行:

if is_paid: 
    self.order.order_payment_complete() # self.order will be SpecializedOrder 
+0

完美,這正是我所需要的。 :) – Nino 2009-08-11 15:34:35

1

你想要的東西被稱爲動態多態性和Django真的很糟糕。 (我能感覺到你的疼痛)

迄今爲止我見過的最簡單的辦法是這樣的:

1)你所有的模型需要這種功能創建一個基類。事情是這樣的:(代碼here公然被盜)

class RelatedBase(models.Model): 
    childclassname = models.CharField(max_length=20, editable=False) 

    def save(self, *args, **kwargs): 
     if not self.childclassname: 
      self.childclassname = self.__class__.__name__.lower() 
     super(RelatedBase, self).save(*args, **kwargs) 

    @property 
    def rel_obj(self): 
     return getattr(self, self.childclassname) 

    class Meta: 
     abstract = True 

2)從該類繼承您的訂單。

3)每當你需要一個Order對象時,使用它的rel_obj屬性,它會返回你的基礎對象。

該解決方案還遠不是優雅,但我還沒有找到更好的......

+0

我想您的解決方案僅僅是由賈勒特以上的contentType解決方案解決方法, 對? – Nino 2009-08-11 15:19:44

+0

@Nino這是更一般的意義上,它可以適用於任何類層次結構,只要它被使用,即您可以查詢父類表和訪問子類對象。但是對於外鍵,是的,這只是一個解決方法。 – 2009-08-12 08:59:16