【问题标题】:Django - How to combine select_related and prefetch_related to reduce the number of queriesDjango - 如何结合 select_related 和 prefetch_related 以减少查询次数
【发布时间】:2020-09-12 02:13:36
【问题描述】:

我想生成一个 json,它是来自多个链接在一起的表的数据聚合(OneToOne 和 ManyToMany 关系)。

models.py

Team(models.Model):
    staff = models.OneToOneField(Staff, on_delete=models.CASCADE, related_name='team_staff')
    function = models.CharField()

Staff(models.Model):
    firstname = models.CharField()
    lastname = models.CharField()
    courses = models.ManyToManyField(Course, related_name='staff_course')

Course(models.models):
    name = models.CharField()
    begin= models.DateField()
    end = models.DateField()

    def __str__(self):
        return '%s - %s' % (self.name, self.begin, self.end)

views.py

def all_team(request):
    team_query = Team.objects.all().select_related('staff')
    team_list = []
        for person in team_query:
            courses = Staff.objects.get(id=person.staff.id).courses.order_by('-begin')
            team_list.append({'fields': {'id': obj.id,
                                         'function': person.function,
                                         'firstname': person.staff.firstname,
                                         'lastname': person.staff.lastname,
                                         'last_course': str(courses.first()),
                                        }})
        json_data = json.dumps(team_list, cls=DjangoJSONEncoder)
        return HttpResponse(json_data, content_type='application/json')

如您所见,这不是很有效。对于团队的每个成员,您都可以进行查询以获取上一门课程。我们可以添加类似的内容:

staff_query = Staff.objects.all().prefetch_related(Prefetch('courses', queryset=Course.objects.only('name').all()))

并将其与 team_query 合并/组合。

提前感谢您的建议

【问题讨论】:

  • 你用的是什么数据库?
  • 目前处于项目阶段。我正在使用 SQLite 文件。当它被部署时,我正在考虑使用 Postgres 服务器。

标签: django python-3.x django-views


【解决方案1】:

您可以使用正常的连接语法从相关字段中预取相关字段:

team_query = (
  Team.objects.all()
  .select_related('staff')
  .prefetch_related(
    Prefetch('staff__courses').order_by('-begin'))
  )
)

那么获得最后一门课程将变为:

'last_course': str(person.staff.courses.first())

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-06
    • 1970-01-01
    • 2021-09-06
    • 2013-05-20
    • 2014-10-12
    • 1970-01-01
    相关资源
    最近更新 更多