我现在使用python / django已有1个月了,我需要帮助,因为我找不到任何类似的问题来寻找我想要的答案。我有工人模型和工作模型。一个工人可以有很多工作。我需要查询工作人员拥有的最新工作。
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对象,包括其先前的作业。我只想向工人查询最新的工作地点和开始日期。
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)
有没有一种方法可以对诸如Worker.job_set.all()
之类的查询使用for循环来获得预期的输出结果
(A, east, 2019-05-11)
(B, west, 2019-01-01)
希望您可以帮助像我这样的新手。先感谢您! :)
答案 0 :(得分:1)
我认为其他两个答案非常简单。他们两个都在解决您现在要解决的问题,但是一旦您拥有越来越多的工人/工作,这些解决方案就会失败,因为它们的所有解决方案都是O(N)。这个解决方案是O(1)。
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
进行单个查询,但BUT将仅对最新工作进行单个查询,其他解决方案将使查询成为PER工作者,这效率低下且速度慢。
有关如何测试所有这些内容的更多背景信息,请参见此示例。 https://gist.github.com/kingbuzzman/ac2ada9c27196fc90c1b75f2d01a6271#file-django_prefetch_limit-py-L163
答案 1 :(得分:0)
您可以在工作人员的经过过滤和排序(按last
,以升序排列)的查询集上使用start_date
方法。
例如,如果工人的名字是foobar
,则可以执行以下操作:
Job.objects.filter(worker__name='foobar').order_by('start_date').last()
这将为您提供名为Job
的工作人员的最后start_date
(基于foobar
)。
首先,如果您以first
的降序排序,您还可以获得start_date
元素:
Job.objects.filter(worker__name='foobar').order_by('-start_date').first()
答案 2 :(得分:0)
例如,您可以对job_set查询集执行排序。您正在寻找类似这样的东西吗?
for worker in Worker.objects.all():
latest_job = worker.job_set.latest('start_date')
print(worker.name, latest_job.location, latest_job.start_date)