Множество общих отношений Django

Я думаю, мне нужно создать "много-ко многим родовым отношениям".

У меня есть два типа участников:

class MemberParticipant(AbstractParticipant):
    class Meta:
        app_label = 'participants'


class FriendParticipant(AbstractParticipant):
    """
    Abstract participant common information shared for all rewards.
    """
    pass

Эти участники могут иметь 1 или более вознаграждений 2 разных видов (модель вознаграждений из другого приложения):

class SingleVoucherReward(AbstractReward):
    """
    Single-use coupons are coupon codes that can only be used once
    """
    pass

class MultiVoucherReward(AbstractReward):
    """
    A multi-use coupon code is a coupon code that can be used unlimited times.
    """

Итак, теперь мне нужно связать все это. Вот как я думал о создании отношений (см. Ниже), будет ли это работать, какие-либо проблемы, которые вы видите?

Предлагаемая модель ссылок ниже:

class ParticipantReward(models.Model):


    participant_content_type = models.ForeignKey(ContentType, editable=False,
                                                        related_name='%(app_label)s_%(class)s_as_participant',
                                                        )
    participant_object_id = models.PositiveIntegerField()
    participant = generic.GenericForeignKey('participant_content_type', 'participant_object_id')


    reward_content_type = models.ForeignKey(ContentType, editable=False,
                                                        related_name='%(app_label)s_%(class)s_as_reward',
                                                        )
    reward_object_id = models.PositiveIntegerField()
    reward = generic.GenericForeignKey('reward_content_type', 'reward_object_id')

Примечание. Я использую Django 1.6

Ответ 1

Ваш подход - это именно то, что нужно сделать с учетом существующих таблиц. Хотя ничего официального (эта дискуссия, включающая основного разработчика в 2007 году, похоже, никуда не ушла), я нашел это сообщение в блоге, которое использует тот же подход (и предлагает его в сторонней библиотеке), а также популярный ответ здесь, который аналогичен, за исключением того, что только одна сторона отношения является общей.

Я бы сказал, что причина, по которой эта функциональность никогда не попадала в ствол django, заключается в том, что, хотя это редкое требование, ее довольно легко реализовать с использованием существующих инструментов. Кроме того, вероятность того, что вы захотите создать обычную таблицу "через", вероятно, достаточно высока, поэтому большинство реализаций конечных пользователей будут в любом случае включать немного пользовательского кода.

Единственным другим потенциально более простым подходом было бы иметь базовые модели участника и вознаграждения с отношениями ManyToMany между ними, а затем использовать наследование нескольких таблиц расширить эти модели в качестве члена/друга и т.д.

В конечном счете вам просто нужно взвесить сложность общего отношения по сравнению с тем, что ваши данные объекта распространяются на две модели.

Ответ 2

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

Как говорит Грег, подход, который вы выбрали, - это хороший способ сделать это.

Тем не менее, я бы не стал квалифицировать многих для многих как "легко реализуемых с использованием существующих инструментов", когда вы хотите использовать такие функции, как обратные отношения или предварительная выборка.

Стороннее приложение django-genericm2m приятно, но, по моему мнению, имеет несколько недостатков (факт, что объекты "сквозной" по умолчанию находятся в одной таблице базы данных и что у вас нет "add" /'remove 'методы - и, следовательно, объемное добавление/удаление).

С учетом этого, поскольку мне нужно было что-то, чтобы реализовать общие отношения "многие ко многим" "путь django", а также потому, что я хотел немного узнать о внутренностях django, я недавно выпустил django-gm2m. Он имеет очень похожий API для django встроенного GenericForeignKey и ManyToManyField (с предварительной выборкой через модели...) и добавляет настройку поведения удаления. Единственное, чего ему не хватает на данный момент, это подходящий интерфейс администратора django.