2009-08-11 28 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