首页 > 解决方案 > Django反向外键

问题描述

我现在使用 python/django 1 个月了,我需要帮助,因为我找不到任何具有我正在寻找的答案的类似问题。我有工人模型和工作模型。一个工人可以有很多工作。我需要查询 Worker 的最新工作。

class Worker(models.Model):
   name = models.CharField(max_length=128)

class Job(models.Model):
   worker = models.ForeignKey(Worker)
   type = models.CharField(max_length=64)
   position = models.CharField(max_length=64)
   location = models.CharField(max_length=128)
   start_date = models.DateField()

我目前正在使用这个示例代码。问题是这会返回类似的 Worker 对象,包括它以前的作业。我只想用最新的工作地点和开始日期查询 Worker。

for employee in Job.objects.all():
   print(employee.worker, employee.location, employee.start_date)

样本输出

(A, north, 2018-01-21)
(A, south, 2018-09-13)
(A, east, 2019-05-11)
(B, west, 2019-01-01)

有没有办法使用 for 循环来查询像Worker.job_set.all()这样的预期输出

(A, east, 2019-05-11)
(B, west, 2019-01-01)

希望你能帮助像我这样的新手。先感谢您!:)

标签: pythondjangopython-2.7django-modelsdjango-views

解决方案


我认为其他两个答案非常简单。他们俩都在解决您现在要解决的问题,但是一旦您拥有越来越多的工人/工作,这些解决方案就会失败,因为他们的所有解决方案都是 O(N*N)。这个解决方案是 O(N)。

    subqry = models.Subquery(Job.objects.filter(worker_id=models.OuterRef('worker_id'))
                                        .order_by('-start_date').values('id')[:1])
    workers = Worker.objects.prefetch_related(models.Prefetch('job_set',
                                                              queryset=Job.objects.filter(id__in=subqry)))

    for worker in workers:
        # no matter what this will always have 1 // or nothing, depending on your logic; if nothing, fix this.
        latest_job = list(worker.job_set.all())[0]  
        print(worker.name, latest_job.location, latest_job.start_date)

这将对Worker其他工作进行一次查询,但只会对最新作业进行一次查询,其他解决方案将对每个工作人员进行查询,这是低效且缓慢的。

有关我如何测试所有这些的更多背景信息,请参阅此示例。https://gist.github.com/kingbuzzman/ac2ada9c27196fc90c1b75f2d01a6271#file-django_prefetch_limit-py-L163


推荐阅读