先决条件:
- 查询集必须返回
文章
- 查询集必须返回唯一的对象
- 不得使用访问数据库的 for 循环(意味着对要注释的 N 个对象进行 N 次查询)
我的模型:
class Report(BaseModel):
ios_report = JSONField()
android_report = JSONField()
class Article(BaseModel):
internal_id = models.IntegerField(unique=True)
title = models.CharField(max_length=500)
short_title = models.CharField(max_length=500)
picture_url = models.URLField()
published_date = models.DateField()
clip_link = models.URLField()
reports = models.ManyToManyField(
"Report", through="ArticleInReport", related_name="articles"
)
class ArticleInReport(BaseModel):
article = models.ForeignKey("core.Article", on_delete=models.CASCADE, related_name='articleinreports')
report = models.ForeignKey("core.Report", on_delete=models.CASCADE, related_name='articleinreports')
ios_views = models.IntegerField()
android_views = models.IntegerField()
@property
def total_views(self):
return self.ios_views + self.android_views
一切都始于按设定时间间隔创建的Report
对象。该报告包含有关文章及其各自观点的数据。一个Report
会通过ArticleInReport
与Article
建立关系,其中保存了Article
中的用户总数< strong>导入报告时。
在我看来,我需要显示以下信息:
- 过去 30 分钟内获得浏览的所有文章。
- 每篇文章都注释有以下信息,这就是我面临的问题:
If present, the number of views the
Article
object had in the lastReport
. If not present, 0.
我的views.py
文件:
reports_in_time_range = Report.objects.filter(created_date__range=[starting_range, right_now]).order_by('created_date')
last_report = reports_in_time_range.prefetch_related('articles').last()
unique_articles = Article.objects.filter(articleinreports__report__in=reports_in_time_range).distinct('id')
articles = Article.objects.filter(id__in=unique_articles).distinct('id').annotate(
total_views=Case(
When(id__in=last_report.articles.values_list('id', flat=True),
then=F('articleinreports__ios_views') + F('articleinreports__android_views')),
default=0, output_field=IntegerField(),
))
对我的思考过程的一些解释:首先,只获取时间范围内相关报告中出现的文章(filter(id__in=unique_articles)
),仅返回不同的文章。接下来,如果文章的 ID 出现在最后报告的文章列表中(当然是通过 ArticleInReport
),则计算该 ArticleInReport< 的 iOS 浏览量 + Android 浏览量
.
上面的注释适用于大多数文章
,但对于其他文章却无缘无故地失败了。我尝试了许多不同的方法,但似乎总是得到错误的结果。
最佳答案
避免数据库命中非常重要,但不是以这个价格。在我看来,您应该将查询拆分为两个或多个查询。拆分查询将提高可读性,也可能提高性能(有时两个简单查询比一个复杂查询运行得更快)。请记住,您拥有 dic、理解和 itertools 的所有功能来处理部分结果。
reports_in_time_range = ( Report
.objects
.filter(created_date__range=[starting_range, right_now])
.order_by('created_date'))
last_report = reports_in_time_range.prefetch_related('articles').last()
report_articles_ids = ( Article
.objects
.filter(articleinreports__report=last_report)
.values_list('id', flat=True)
.distinct())
report_articles = ( Article
.objects
.filter(id__in=report_articles_ids)
.annotate( total_views=Sum(
F('articleinreports__ios_views') +
F('articleinreports__android_views'),
output_field=IntegerField()
)))
other_articles = ( Article
.objects
.exclude(id__in=report_articles_ids)
.annotate( total_views=ExpressionWrapper(
Value(0),
output_field=IntegerField())
)))
articles = report_articles | other_articles
关于Django 复杂注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52689949/