应用程序的松散耦合&模型继承

时间:2009-08-11 10:40:07

标签: django django-models

我有一个关于Django的设计问题。我不太确定如何将应用松散耦合原则应用于这个特定问题:

我有一个管理订单的订单应用程序(在网上商店)。在这个order-app中我有两个类:

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()方法。但是,由于Payment与Order而不是SpecializedOrder相关联,因此调用基本订单的order_payment_complete()方法。

我真的不知道实现这种设计的最佳方式。也许我完全不在 - 但我想构建这个订单应用程序,以便我可以将它用于多种用途,并希望尽可能保持通用。

如果有人可以帮助我,那就太好了! 谢谢, 尼诺

2 个答案:

答案 0 :(得分:4)

我认为您正在寻找的是来自ContentTypes框架的GenericForeignKey,它与JDBC包中的Django一起提供。它处理记录子类实例的类型和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

答案 1 :(得分: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属性,该属性将返回基础对象。

这个解决方案远非优雅,但我还没找到更好的解决方案......