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

好听!很高兴帮助 –