Множество общих отношений 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.