如何从 django 中的单个表检索多态模型 - 或者如何在 django 中实现多态行为

发布于 2024-11-10 12:49:23 字数 1354 浏览 0 评论 0原文

我可以从单个数据库表中读取多态模型,其行为取决于模型的(布尔)字段吗?

在我的一个模型中,如果实例是“向前”与“向后”或“向左”与“向右”,则行为会略有不同。这会导致大量的 if 子句和代码重复。所以我想要有一个模型的前向和后向变体来封装不同的行为。

但是我怎样才能让模型管理器返回正确类的实例呢?我是否必须覆盖模型的 __init__

也许用一个例子更容易解释。我正在做什么:

class Foo(models.Model):
    forward = models.BooleanField()
    other_fields = ...

    def do_foobar(bar):
        if self.forward:
            gap = bar.end_pos - bar.current_pos
            self.do_forward_move(max = gap)
            if self.pos==bar.end_pos:
                and so on ...
        else:
            gap = bar.current_pos - bar.start_pos
            self.do_backward_move(max = gap)
            if self.pos==bar.start_pos:
                and so on ...

我想要做什么:

class Foo(models.Model):
    forward = models.BooleanField()
    other_fields = ...

    def __init__(*args, **kwargs):
        """ return ForwardFoo or BackwardFoo 
        depending on the value of 'forward'"""
        How?

    def do_foobar(bar):
        gap = self.calculate_gap(bar)
        self.do_move(max = gap)
        if self.end_point_reached():
            and so on ...

class ForwardFoo(Foo):
    def calculate_gap(bar):
        return bar.end_pos - bar.current_pos
and so on ...

for f in Foo.objects.all():
    f.do_foobar(bar)

或者是否有一种完全不同的方法来避免这种代码重复?

Can I read polymorphic models from a single database table, with their behaviour depending on a (boolean) field of the model?

In one of my models the behaviour is slightly different if the instance is 'forward' vs. 'backward' or 'left' vs. 'right'. That leads to a lot of if-clauses and code duplication. So I want to have a Forward- and a Backward-variant of the model that encapsulate the different behaviours.

But how can I make the models manager return the instances of the right classes? Do I have to overwrite __init__ of the model?

Maybe it's easier to explain with an example. What I'm doing:

class Foo(models.Model):
    forward = models.BooleanField()
    other_fields = ...

    def do_foobar(bar):
        if self.forward:
            gap = bar.end_pos - bar.current_pos
            self.do_forward_move(max = gap)
            if self.pos==bar.end_pos:
                and so on ...
        else:
            gap = bar.current_pos - bar.start_pos
            self.do_backward_move(max = gap)
            if self.pos==bar.start_pos:
                and so on ...

What I want to do:

class Foo(models.Model):
    forward = models.BooleanField()
    other_fields = ...

    def __init__(*args, **kwargs):
        """ return ForwardFoo or BackwardFoo 
        depending on the value of 'forward'"""
        How?

    def do_foobar(bar):
        gap = self.calculate_gap(bar)
        self.do_move(max = gap)
        if self.end_point_reached():
            and so on ...

class ForwardFoo(Foo):
    def calculate_gap(bar):
        return bar.end_pos - bar.current_pos
and so on ...

for f in Foo.objects.all():
    f.do_foobar(bar)

Or is there a totally different way to avoid this kind of code duplication?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

溺ぐ爱和你が 2024-11-17 12:49:23

代理模型:

class Foo(models.Model):
    # all model attributes here

class ForwardFooManager(models.Manager):
    def get_query_set(self, *args, **kwargs):
        qs = super(ForwardFooManager, self).get_query_set(*args, **kwargs)
        return qs.filter(forward=True)

class ForwardFoo(Foo):
    class Meta:
        proxy = True

    objects = ForwardsFooManager()

    # methods for forward model

class BackwardFooManager(models.Manager):
    def get_query_set(self, *args, **kwargs):
        qs = super(BackwardFooManager, self).get_query_set(*args, **kwargs)
        return qs.filter(forward=False)

class BackwardFoo(Foo):
    class Meta:
        proxy = True

    objects = BackwardFooManager()

    # methods for backward model

上面创建了两种代理模型:一种用于前向,一种用于后向。代理模型没有自己的数据库表;它们使用与其继承的模型相同的数据库表。 (这也意味着您不能向代理模型添加任何其他字段,只能添加方法。)

还有一个自定义管理器,用于强制每个字段仅返回属于每个字段的项目子集。只需添加您需要的任何特定方法即可完成。

Proxy models:

class Foo(models.Model):
    # all model attributes here

class ForwardFooManager(models.Manager):
    def get_query_set(self, *args, **kwargs):
        qs = super(ForwardFooManager, self).get_query_set(*args, **kwargs)
        return qs.filter(forward=True)

class ForwardFoo(Foo):
    class Meta:
        proxy = True

    objects = ForwardsFooManager()

    # methods for forward model

class BackwardFooManager(models.Manager):
    def get_query_set(self, *args, **kwargs):
        qs = super(BackwardFooManager, self).get_query_set(*args, **kwargs)
        return qs.filter(forward=False)

class BackwardFoo(Foo):
    class Meta:
        proxy = True

    objects = BackwardFooManager()

    # methods for backward model

The above creates two proxy models: one for forward, one for backward. Proxy models do not have their own database table; they use the same database table as the model they inherit from. (This also means you cannot add any additional fields to the proxy model, only methods.)

There's also a custom manager for to force each one to only return the subset of items that belong to each. Just add whatever specific methods you need and you're done.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文