2013-07-23 21 views
0

我知道filtering by property對於Django來說是不可能的,因爲過濾是在數據庫級完成的,並且屬性存在於Python代碼中。但是,我有以下情況:Django的高效替代過濾器屬性

一方面,我有模型RegisteredUser另一方面Subscription。用戶可以有多個訂閱,一個訂閱來自一個用戶,而一個用戶有一個訂閱或沒有活動訂閱。

要實現這一點,我已經從SubscriptionRegisteredUser外鍵,並在RegisteredUser(爲該用戶創建最新的訂閱)的屬性subscription指向活動的一個或沒有,如果他還沒有任何訂閱。

這將是過濾訂閱「白金」,「黃金」,「銀」......的用戶最有效的方法......?我可以做一個「獲取所有訂閱」,然後遍歷它們來檢查每一個匹配。但是,這將非常昂貴,如果我必須爲每種訂閱類型執行相同的流程,則成本將爲s * u(其中s是不同訂閱的數量,u是用戶數量)。

任何幫助將不勝感激。提前致謝!

UPDATE:

當我第一次說明了問題,我並沒有包括所有相關 模型簡化豆蔻。但是,當你問我的模型,有些人還沒有理解我 (也許我還不夠清楚),你有代碼。 我簡化了模型並剝離了現在不重要的代碼。

我在這裏有什麼? A RegisteredUser可以有很多訂閱(因爲他可以根據需要多次更改它 ),訂閱僅來自一個用戶。用戶只有 一個當前訂閱,這是最新的一個,並且由屬性 subscription返回。 Subscription附有Membership,這是其 slug可以是模型:鉑,金,銀等

我需要做什麼?我需要查找Content其具有特定類型的成員資格。 如果屬性方法的工作,我已經做了這樣的:

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")) 
+0

試圖https://docs.djangoproject.com/en/dev/ref/models/querysets/? – Hamish

+0

@Hamish我不明白你的意思......我到底應該尋找什麼? – Caumons

+0

原始查詢現在派上用場?實際上你可以發佈你的模型代碼嗎? –

回答

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() 
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") 
+0

或'gold_silver_platinum = RegisteredUser.objects.filter(subscriptions_kind__in = ['g','s','p'])' –

+0

這不是我所需要的,這個問題比這個微不足道的場景複雜得多。您可以查看我的更新問題,該問題現在包含代碼。乾杯! – Caumons