gpt4 book ai didi

python - Django:复杂的注释,如何避免for循环?

转载 作者:行者123 更新时间:2023-12-01 01:43:33 24 4
gpt4 key购买 nike

对于使用 Google Realtime Analytics API 的分析应用,我的 models.py 定义如下:

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会通过ArticleInReportArticle建立关系,其中保存了Article中的用户总数< strong>导入报告时。

在我看来,我需要显示以下信息:

  • 过去 24 小时内收到浏览的所有文章。
  • 每篇文章都注释有以下信息:
  • 如果存在,则为 Article 对象在上一个Report 中的浏览次数。如果不存在,则为 0。

我在我的 views.py 中实现了以下目标:

reports_in_time_range = Report.objects.filter(created_date__range=[starting_range, right_now])
last_report = Report.objects.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(articleinreports__report=last_report,
then=(F("articleinreports__ios_views") + F("articleinreports__android_views"))), default=0, output_field=IntegerField(),
))

sorted_articles = sorted(articles, key=operator.attrgetter('total_views'), reverse=True)

但我还需要为每篇显示的文章提供一个“趋势图”,其中包含以下信息:

  1. X 轴:过去 6 小时内导入的所有报告(或更确切地说,报告日期),无论文章 ID 是否出现在其中。
  2. Y 轴:每个报告中 total_views 的值:如果文章存在,则显示 total_views,如果不存在,则返回 0 >.

我无法找到一种有效的方法来做到这一点而不诉诸多个 for 循环。我目前的方法是将以下方法添加到 Article 模型中:

class Article(BaseModel):

def get_article_data_for_reports(self, report_objs):
graph_dict = {}
graph_dict['x_vals'] = [x.created_date for x in report_objs]
graph_dict['y_vals'] = []
for passed_report in report_objs:
try:
graph_dict['y_vals'].append(ArticleInReport.objects.get(article=self, report=passed_report).total_views)
except ArticleInReport.DoesNotExist:
graph_dict['y_vals'].append(0)
print(graph_dict)
return graph_dict

views.py 文件中我这样做:

    context["articles"] = sorted_articles
context["article_graphs"] = {}

for article in sorted_articles:
context["article_graphs"][article.internal_id]= article.get_article_data_for_reports(xhours_ago_reports)

然后我可以以某种方式在 View 的上下文中使用它。但在继续之前,我想知道是否有更好的方法来做到这一点。每次刷新时,页面加载时间从几毫秒飙升至 5-9 秒。

最佳答案

from django.db.models import F


reports = Report.objects.all() # Filter reports here

# This creates LEFT OUTER JOIN with all ArticleInReport, so each
# Article will appear in result once per each report which includes it
articles_with_reports = Article.objects.annotate(
report_id=F('articleinreports__report_id')
)
# We are only interested in some reports
articles_in_reports = articles_with_reports.filter(
report_id__in=reports.values('id')
)
# As each result row is actually ArticleInReport, this effectively gives
# amount of views per article per report
articles_with_views = articles_in_reports.annotate(
views=(
F('articleinreports__ios_views')
+ F('articleinreports__android_views')
)
)
# Now do some processing in python - it's cheap
# We need dictionary to create final chart data
articles_map = {} # {Article: {report_id: article_with_view}}
for article in articles_with_views:
articles_map.setdefault(article, {})
articles_map[article][article.report_id] = article.views

article_graphs = {}
# Force-evaluate to cache Reports
# Actually this would happen automatically, but to be certain...
reports = list(reports)
# As we want all Articles, we have to fetch them
for article in Article.objects.all():
x_vals = []
y_vals = []
# Now for each report we will set article.views or 0
# this will execute only once
for report in reports:
x_vals.append(report.created_date)
if (
article in articles_map
and report.id in articles_map[article]
):
# We have views for this article in this record
y_vals.append(articles_map[article][report.id])
else:
# Defaults
y_vals.append(0)
article_graphs[article] = {
'x_vals': x_vals,
'y_vals': y_vals
}

# Finally, we have article_graphs
# {
# Article: {
# 'x_vals': [Date, Date, Date],
# 'y_vals': [100, 0, 50]
# },
# ....
# }

更新

要仅为在最近的报告中至少出现 1 次的 Articles 构建图表,我们只想直接使用 articles_map

article_graphs = {}
# Force-evaluate to cache Reports
# Actually this would happen automatically, but to be certain...
reports = list(reports)
for article, views_by_report in articles_map.items():
x_vals = []
y_vals = []
# Now for each report we will set article.views or 0
for report in reports:
x_vals.append(report.created_date)
y_vals.append(views_by_report.get(report.id, 0))
article_graphs[article] = {
'x_vals': x_vals,
'y_vals': y_vals
}

关于python - Django:复杂的注释,如何避免for循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51628114/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com