1

関連する 2 つのモデルがあります。

class FirstModel(models.Model):
    base_value = models.FloatField()

class SecondModel(models.Model):
    parent = models.ForeignKey(FirstModel)

    @property
    def parent_value(self):
        return self.parent.base_value

    @property
    def calculate(self):
        return self.parent_value + 1

一般に、SecondModel.calculateは主に関連する のコンテキストで使用されますFirstModelcalculateただし、一時的な値を として呼び出すことができるようにしたい場合がありparent_valueます。このようなもの:

foo = SecondModel()
# would look in the database for the related FirstModel and add 1 to its base_value
foo.calculate

foo.parent_value = 10
foo.calculate      # should return 11

parent_valueは読み取り専用プロパティであるため、明らかにこれを行うことはできません。また、この種の機能が必要な SecondModel に似た多くの異なるモデルがあります。

私はいくつかのことを考えて試しましたが、どれもうまくいかないようです:

1) Django プロキシ モデルを作成する- 可能ですが、オブジェクトの数がかなり多いため、同様のコードをたくさん作成することになります。また、プロパティのオーバーライドに関連するバグがあるようです: https://code.djangoproject.com/ticket/16176。しかし、次のようになります。

class ModelProxy(SecondModel):
    class Meta:
         proxy = True
    def __init__(self, temp_value):
         self.parent_value = temp_value

2)インスタンスのプロパティをオーバーロードするparent_value- 次のように:

foo = SecondModel()
setattr(foo, 'parent_value', 10)

ただし、プロパティはインスタンスではなくクラスのメンバーであるため、これを行うことはできません。そして、インスタンスに一時的な値を設定したいだけです

3)メタクラスまたはクラス ジェネレーター? - 複雑すぎるようです。また、メタクラスを使用して、models.Model の子であるクラスを動的に生成するとどうなるかはわかりません。データベース テーブルが同期していないと問題が発生しますか?

4)適切なゲッターとセッターでプロパティを書き換えますか? - プロパティを設定できるように SecondModel を書き直すのが解決策でしょうか?

助言がありますか?

4

3 に答える 3

1

I believe a mixin would achieve what you want to do, and provide a simple and reusable way of supporting temporary values in your calculations. By mixing the below example into each model you want this behaviour on you can then:

  • Set a temporary parent value on each model
  • When calculate is called, it will check whether there is a property parent_value available, and if not it will use the temporary parent value in the calculation.

The code below should achieve what you are looking for - apologies I haven't been able to test it yet but it should be about right - please let me know if any problems that need editing.

class CalculateMixin(object):

    @property
    def temp_parent_value(self):
        return self._temp_parent_value

    @temp_parent_value.setter
    def temp_parent_value(self, value):
        self._temp_parent_value = value

    @property
    def calculate(self):
        parent_value = self.parent_value if self.parent_value else self.temp_parent_value
        return parent_value + 1


class SecondModel(models.Model, CalculateMixin):
    parent = models.ForeignKey(FirstModel)

    self.temp_parent_value = 'Whatever value you desire'

    @property
    def parent_value(self):
        return self.parent.base_value
于 2013-06-25T09:58:15.840 に答える
0

以下に示すmixin を使用して、必要なことを実行できると思います。PropertyOverrideMixinプロパティ値が利用できない場合は、接頭辞が付いた同じプロパティを探しますtemp_。これにより、実際のプロパティ値を検索できない場合に使用できる一時的な値を提供できます。

以下は、ミックスイン、いくつかのモデル例、およびこれがどのように機能するかを示す単体テストです。これがあなたの問題に適応できることを願っています!最後に、ここでのプロパティは通常のオブジェクト属性と交換可能であり、それでもすべて機能することに注意してください。

from unittest import TestCase


class PropertyOverrideMixin(object):

    def __getattribute__(self, name):
        """
        Override that, if an attribute isn't found on the object, then it instead
        looks for the same attribute prefixed with 'temp_' and tries to return
        that value.
        """

        try:
            return object.__getattribute__(self, name)
        except AttributeError:
            temp_name = 'temp_{0}'.format(name)
            return object.__getattribute__(self, temp_name)


class ParentModel(object):

    attribute_1 = 'parent value 1'


class Model(PropertyOverrideMixin):

    # Set our temporary property values
    @property
    def temp_attribute_1(self):
        return 'temporary value 1'

    @property
    def temp_attribute_2(self):
        return 'temporary value 2'

    # Attribute 1 looks up value on its parent
    @property
    def attribute_1(self):
        return self.parent.attribute_1

    # Attribute 2 looks up a value on this object
    @property
    def attribute_2(self):
        return self.some_other_attribute


class PropertyOverrideMixinTest(TestCase):

    def test_attributes(self):
        model = Model()

        # Looking up attributes 1 and 2 returns the temp versions at first
        self.assertEquals('temporary value 1', model.attribute_1)
        self.assertEquals('temporary value 2', model.attribute_2)

        # Now we set the parent, and lookup of attribute 1 works on the parent
        model.parent = ParentModel()
        self.assertEquals('parent value 1', model.attribute_1)

        # now we set attribute_2, so this gets returned and the temporary ignored
        model.some_other_attribute = 'value 2'
        self.assertEquals('value 2', model.attribute_2)
于 2013-07-02T12:12:38.273 に答える