【问题标题】:Any way to use a Django Model as an Interface?有什么方法可以将 Django 模型用作接口?
【发布时间】:2014-12-16 22:36:01
【问题描述】:

我有许多子类的基类,子类中唯一改变的是某个方法(模板模式)。但是我被卡住了,无法让它工作。

class Base(models.Model):
    _value = models.CharField(max_length=200)
    _name = models.CharField(max_length=200)
    user = models.ForeignKey(User, related_name="some_set")

    #used as a property
    def value():
        def fget(self):
            self.refresh()
            return self._value

    def refresh(self):
        raise NotImplementedError("..")

class Subclass1(Base):
    def refresh(self):
        self._value = some_val

class Subclass2(Base):
    def refresh(self):
        self._value = some_other_val

我希望能够将整个相关集视为同一个实体,并在每个实体上调用 value 属性,每个实体都遵循其自己实现的刷新版本,即

for x in user.some_set.all():
    print x.value

但在这一点上似乎不可能,即使在超类中删除刷新也是如此。我也考虑过使用 Strategy 模式并使用 ForeignKey 关系来调用该方法,但我仍然必须在 ForeignKey 中有一个子类派生自的基类。

【问题讨论】:

    标签: python django python-2.7 design-patterns django-1.6


    【解决方案1】:

    使用Proxy Models

    来自文档

    然而,有时,您只想更改模型的 Python 行为 - 可能是更改默认管理器,或添加新方法。

    这就是代理模型继承的用途:为原始模型创建代理。您可以创建、删除和更新代理模型的实例,所有数据都将被保存,就像您使用原始(非代理)模型一样。不同之处在于您可以更改默认模型排序或代理中的默认管理器等内容,而无需更改原始内容。

    【讨论】:

    • 它在正确的路径上,但仍然不允许我在获取相关集时调用新定义的方法refresh
    【解决方案2】:

    我可能没有抓住重点,但你尝试过 Django Model Utils 吗?

    https://bitbucket.org/carljm/django-model-utils/src

    如果您查看继承管理器并对模型进行相关更改,您应该能够按照以下方式进行查询:

    entities = Base.objects.filter(user=my_user_obj).select_subclasses()
    for entity in entities:
        print entity.value
    

    【讨论】:

    • 这很接近,但我无法让它解析到子类的最深层次。当我将 InteritanceManager 放在子类上时(我实际上有 2 层深),它不会解析为子类
    • 你的模型继承有多深?
    • 比上面多了一层,抱歉应该包括那个。
    • 文档声明如果使用 >=django 1.6 那么它应该满足孙子继承。从你的问题的标签来看是这样的吗?
    • 是的 - 我自己也注意到了。但是,如果我将objects = InheritanceManager() 贴在根类上,当我调用select_subclasses 时,它只会深入一层,如果我将它贴在下一个类上,它就会自行解决。
    【解决方案3】:

    我最终使用了 GenericForeignKey 的策略模式

    class Base(models.Model):
        _name = models.CharField(max_length=200)
        user = models.ForeignKey(User, related_name="some_set")
        content_type = models.ForeignKey(ContentType)
        object_id = models.PositiveIntegerField()
        strategy = GenericForeignKey()
    
        #used as a property
        def value():
            def fget(self):
                return self.strategy.value
    
    class Strategy1(models.Model):
        #some other definitions
        def value():
            def fget(self):
                return some_var
    
    class Strategy2(models.Model):
        #some other definitions
        def value():
            def fget(self):
                return some_other_var
    

    这让我可以做到for x in user.some_set.all(): print x.value

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-23
      • 2011-04-20
      • 1970-01-01
      • 2016-07-18
      • 2011-06-20
      • 1970-01-01
      • 2017-12-18
      • 2012-11-23
      相关资源
      最近更新 更多