Самореферентные отношения или разные модели (реферальная система Django)
Первый пример реализует самореферентные отношения:
class User(models.Model):
username = models.CharField(max_length=50, null=True)
referrer = models.ForeignKey("self", related_name='referrals', null=True, blank=True)
referrer_bonus = models.IntegerField(default=0)
referral_bonus = models.IntegerField(default=0)
Во втором варианте используется промежуточная модель:
class Referral(models.Model):
referrer = models.ForeignKey(User, on_delete=models.PROTECT, related_name="referrals")
referral = models.OneToOneField(User, on_delete=models.PROTECT, related_name='referral')
referrer_bonus = models.IntegerField(default=0)
referral_bonus = models.IntegerField(default=0)
Вопрос в том, что у одного реферала может быть один реферер. Но у реферала может быть много рефералов.
Какой подход будет лучше, если мне нужно использовать анотацию для расчета общего бонуса и количества рефералов. И какой вариант будет оптимальным по производительности?
Нет смысла использовать промежуточную модель: если у каждого User
есть (максимум) один реферал, вы только усложните ситуацию, если добавите дополнительную модель: потребуются дополнительные запросы, чтобы получить (id
) реферала, и, кроме того, для расчета бонуса потребуется перечисление элементов.
Вы можете ссылаться на self
, как вы уже делали в первом примере:
class User(models.Model):
username = models.CharField(max_length=50, null=True)
referrer = models.ForeignKey(
'self', related_name='referrals', null=True, blank=True
)
# no referrer_bonus/referral_bonus
Однако вам не нужно хранить referrer_bonus
или referral_bonus
в явном виде. Вы можете просто вычислить их при необходимости, сделав аннотацию, например:
from django.db.models import Count
User.objects.annotate(referral_bonus=Count('referrals') * bonus_per_referral).get(
id=my_id
)
Это предотвращает рассинхронизацию referral_bonus
в конечном итоге.