【问题标题】:Loose coupling of apps & model inheritance应用程序和模型继承的松散耦合
【发布时间】:2009-08-11 10:40:07
【问题描述】:

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

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

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

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    我认为您正在寻找的是 ContentTypes 框架中的 GenericForeignKey,它在 contrib 包中随 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
    

    【讨论】:

    • 完美,这正是我所需要的。 :)
    【解决方案2】:

    你想要的东西叫做动态多态性,而 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 属性,该属性将返回底层对象。

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

    【讨论】:

    • 我猜你的解决方案只是 jarret 对上述 contenttype 解决方案的一种解决方法,对吧?
    • @Nino 在某种意义上它更通用,它适用于任何类层次结构,无论何时使用它,即您可以查询父类表并访问子类对象。但是对于外键,是的,这只是一种解决方法。
    猜你喜欢
    • 2011-01-20
    • 2012-02-27
    • 2017-06-05
    • 1970-01-01
    • 2013-05-06
    • 2020-10-26
    • 2011-02-22
    • 1970-01-01
    • 2012-02-18
    相关资源
    最近更新 更多