1

我知道使用 Django 无法按属性进行过滤,因为过滤是在数据库级别完成的,并且属性存在于 Python 代码中。但是,我有以下情况:

一方面,我有模型RegisteredUser另一方面Subscription。一个用户可以有多个订阅,一个订阅来自一个用户,一个用户有一个或没有有效订阅。

为了实现这一点,我有一个来自Subscriptionto的外键RegisteredUser和一个指向活动的属性subscriptionRegisteredUser为该用户创建的最新订阅),如果他没有任何订阅,则没有。

过滤订阅“白金”、“黄金”、“白银”...的用户最有效的方法是什么?我可以做一个“获取所有订阅”,然后遍历它们以检查每个订阅是否匹配。但这真的很贵,如果我必须为每种订阅类型执行相同的过程,那么成本将是 s * u(其中s是不同订阅u的数量,是用户的数量)。

任何帮助将不胜感激。提前致谢!

更新:

当我第一次解释这个问题时,我没有包括所有与简化相关的模型。但是当您向我询问模型并且你们中的一些人还没有理解我(也许我不够清楚)时,这里有代码。我已经简化了模型并删除了现在不重要的代码。

我这里有什么?ARegisteredUser可以有很多订阅(因为他可以根据需要多次更改),并且订阅仅来自一个用户。用户当前只有一个订阅,这是最新的订阅,由属性返回 subscriptionSubscription附有Membership,这是 slug可以是:铂金,金,银等的模型。

我需要什么?我需要查找具有特定成员资格的人Contentauthor如果属性方法有效,我会这样做:

Content.objects.filter(author__id__in=RegisteredUser.objects.filter(
    subscription__membership__slug="gold"))

但是我不能这样做,因为过滤时不能使用属性!

我认为我可以解决将属性创建的“虚拟”关系转换为真正的 ForeignKey 的问题,但这可能会导致副作用,因为我应该在每次用户更改其订阅时手动更新它,现在它是自动的!有更好的想法吗?

非常感谢!

class RegisteredUser(AbstractUser):
    birthdate = models.DateField(_("Birthdate"), blank=True, null=True)
    phone_number = models.CharField(_("Phone number"), max_length=9, blank=True, default="")

    @property
    def subscription(self):
        try:
            return self.subscriptions_set.filter(active=True).order_by("-date_joined",
                "-created")[0]
        except IndexError:
            return None


class Subscription(models.Model):
    date_joined = models.DateField(_("Date joined"), default=timezone.now)
    date_canceled = models.DateField(_("Date canceled"), blank=True, null=True)
    subscriber = models.ForeignKey(AUTH_USER_MODEL, verbose_name=_("Subscriber"),
        related_name="subscriptions_set")
    membership = models.ForeignKey(Membership, verbose_name=_("Membership"),
        related_name="subscriptions_set")
    created = models.DateTimeField(_("Created"), auto_now_add=True)
    last_updated = models.DateTimeField(_("Last updated"), auto_now=True)
    active = models.BooleanField(_("Active"), default=True)


class Membership(models.Model):
    name = models.CharField(_("Name"), max_length=15)
    slug = models.SlugField(_("Slug"), max_length=15, unique=True)
    price = models.DecimalField(_("Price"), max_digits=6, decimal_places=2)
    recurring = models.BooleanField(_("Recurring"))
    duration = models.PositiveSmallIntegerField(_("Duration months"))


class Content(models.Model):
    author = models.ForeignKey(AUTH_USER_MODEL, verbose_name=_("Author"),
        related_name="contents_set")
    title = models.CharField(_("Title"), max_length=50)
    slug = models.SlugField(_("Slug"), max_length=70, unique=True)
    content = RichTextField(_("Content"))
    date = models.DateField(_("Date"), default=timezone.now)
    published = models.BooleanField(_("Published"))
4

2 回答 2

1

最后,为了解决这个问题,我用subscription一个真正的外键替换了这个属性,并添加了一个信号来附加RegisteredUser创建的订阅。

外键:

subscription = models.ForeignKey(Subscription, verbose_name=_("Subscription"),
    related_name='subscriber_set', blank=True, null=True)

信号:

@receiver(post_save, sender=Subscription)
def signal_subscription_post_save(sender, instance, created, **kwargs):
    if created:
        instance.subscriber.subscription = instance
        instance.subscriber.save()
于 2013-08-05T22:40:04.483 回答
0

我认为您的模型类似于:

KIND = (("p", "platinum"), ("g","gold"), ("s","silver"),)

class RegisteredUser(models.Model):
    # Fields....

class Subscription(models.Model):
    kind = models.CharField(choices=KIND, max_len=2)
    user = models.ForeignKey(RegisteredUser, related_name="subscriptions")

现在,您可以执行以下操作:

gold_users = RegisteredUser.objects.filter(subscriptions_kind="g")
silver_users = RegisteredUser.objects.filter(subscriptions_kind="s")
platinum_users = RegisteredUser.objects.filter(subscriptions_kind="p")

使其适应您的模型

希望有所帮助

编辑

Now, With your models, I think you want something like:

content_of_golden_users = Content.objects.filter(author__subscriptions_set__membership__slug="golden")

content_of_silver_users = Content.objects.filter(author__subscriptions_set__membership__slug="silver")

content_of_platinum_users = Content.objects.filter(author__subscriptions_set__membership__slug="platinum")
于 2013-07-23T03:16:39.443 回答