0

所以我一直被困在設計問題的最後幾天,並沉沒了無數小時,沒有用。DJANGO - Queryset和模型設計

我的問題是,我希望返回所有活動的文章。我已經在模型中做了一個方法,但是我不能使用這將是世界上最好的解決方案的.filter(is_active=True)

因此,現在我已經在ArticleManager中將該方法變成了一個長過濾器,問題是我似乎無法找到一種方式來以對我有用的方式計算當前點擊次數。 (Article模型中的current_clicks方法就是我的目標)。

Models.py

class ArticleManager(models.Manager): 
    def get_queryset(self): 
      return super(ArticleManager, self).get_queryset().filter(article_finish_date=None).filter(article_publish_date__lte=timezone.now()) 
#this is where i need something to the effect of .filter(article_max_clicks__gt=click_set.count()) 

    class Article(models.Model): 
     article_name_text = models.CharField(max_length=200) 
     article_max_clicks = models.IntegerField(default=0) 
     article_creation_date = models.DateTimeField('date created') 
     article_publish_date = models.DateTimeField('date published', null=True, blank=True) 
     article_finish_date = models.DateTimeField('date finished', null=True, blank=True) 
     def __str__(self): 
      return self.article_name_text 
     def is_active(self): 
      if self.article_finish_date==None: 
       if self.article_publish_date <= timezone.now(): 
        return self.current_clicks() < self.article_max_clicks 
       else: 
        return False 
      else: 
       return False 
     def current_clicks(self): 
      return self.click_set.count() 
     is_active.boolean = True 
     actives = ArticleManager() 

class Click(models.Model): 
    click_article = models.ForeignKey(Article, on_delete=models.CASCADE) 
    click_user = models.ForeignKey(User, on_delete=models.CASCADE) 
    click_date = models.DateTimeField('date clicked') 
    def __str__(self): 
     return str(self.id) + " " + str(self.click_date) 

這是點擊如何在views.py創建如果這有助於

article.click_set.create(click_article=article, click_user=user, click_date=timezone.now()) 

如果任何人有任何形式的我應該怎麼abouts做到這一點的想法將不勝感激!

非常感謝,只是讓我知道你是否需要任何信息!

回答

1

Django的annotate functionality非常適合在查詢時添加屬性。從文檔 -

可以使用annotate()子句生成每個對象的摘要。當指定annotate()子句時,QuerySet中的每個對象都將使用指定的值進行註釋。

爲了保持您的查詢性能,您可以在管理器中使用它,而不是對每篇文章進行相關對象的調用(可能非常緩慢)。一旦你有一個註釋的屬性,你可以在你的查詢中使用它。由於Django只在調用對象時執行查詢,因此您可以使用此註釋而不是來計算click_set,它將調用每個相關項目的單獨查詢。 current_clicks方法可能對您仍然有用,但如果將它用於多篇文章,您的查詢將快速加起來,並導致性能下降。

請注意 - 我添加了一個related_nameclicks關鍵字arg到您的click_article字段以便使用它來代替'click_set'。

另外,您會在下面的查詢中看到使用Q objects。這可以讓我們將多個過濾器連接在一起。這些可以在使用AND(,)/ OR(|)操作數時嵌套。於是,則Q對象的閱讀以下將是:

找到所有的文章,其中文章發佈日期早於現在(文章沒有結束日期或文章完成日期後現在)

from django.db.models.query import Q,Count 

class ArticleManager(models.Manager): 
    def get_queryset(self): 
     return super(ArticleManager, self).get_queryset().filter(
        Q(article_publish_date__lte=timezone.now()), 
        (Q(article_finish_date__isnull=True)| 
         Q(article_finish_date__gte=timezone.now()) 
       ).annotate(
        click_count=Count('clicks') 
       ).filter(
        article_max_clicks__gt=click_count 
       ) 

class Article(models.Model): 
    actives = ArticleManager() 
    def current_clicks(self): 
     return self.clicks.count() 

# Now you can call Article.actives.all() to get all active articles   

class Click(models.Model): 
    click_article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='clicks') # added a related_name for more explicit calling of prefetch_related 
+0

喜伊恩, 感謝您的幫助,但我已經試過這段代碼,我仍然遇到問題。首先,我相信你錯過了一個括號,或者在get_queryset方法中放了太多。我已經玩了這個,發現但是我添加或刪除括號我得到'NameError在/ 名稱'click_count'未定義'爲錯誤。你可以幫我嗎?非常感謝! – ThankYOU

+0

剛剛找出解決方案,已編輯解決方案中的代碼。再次感謝您的幫助,我非常感謝! +1 – ThankYOU

+0

好聽!很高興幫助 –