Как извлечь полиморфную модель из одной таблицы в django - или как реализовать полиморфное поведение в django - PullRequest
0 голосов
/ 31 мая 2011

Могу ли я читать полиморфные модели из одной таблицы базы данных, причем их поведение зависит от (логического) поля модели?

В одной из моих моделей поведение немного отличается, если экземпляр «вперед» против «назад» или «влево» против «вправо». Это приводит к большому количеству 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)

Или есть совершенно другой способ избежать такого рода дублирования кода?

1 Ответ

1 голос
/ 31 мая 2011

Модели прокси:

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

Приведенное выше создает две модели прокси: одна для прямого, другая для обратного.Модели прокси не имеют своей собственной таблицы базы данных;они используют ту же таблицу базы данных, что и модель, от которой они наследуют.(Это также означает, что вы не можете добавить какие-либо дополнительные поля в модель прокси, только методы.)

Существует также собственный менеджер, который заставляет каждый из них возвращать только подмножество принадлежащих ему элементов.для каждого.Просто добавьте все необходимые методы, и все готово.

...