如何使用 prefetch_related 获取 Django 相关模型中的最新位置
Posted
技术标签:
【中文标题】如何使用 prefetch_related 获取 Django 相关模型中的最新位置【英文标题】:How to get latest position in Django's related model with prefetch_related 【发布时间】:2021-11-01 02:55:45 【问题描述】:我一直在尝试根据 EmployeePosition 模型中的生效日期获取员工的最新晋升,该模型与 Employee 模型具有多对一关系。
根据我的研究,我找到了一种预取数据的方法,但我得到了多个结果,因为我无法弄清楚如何从生效日期过滤我们的值。
以下是模型:
class Employee(models.Model):
SENIOR = 'Sr'
JUNIOR = 'Jr'
FIRST = 'I'
SECOND = 'II'
THIRD = 'III'
GENERATIONAL_SUFFIX = [
(SENIOR, 'Senior'),
(JUNIOR, 'Junior'),
(FIRST, 'First'),
(SECOND, 'Second'),
(THIRD, 'Third'),
]
MALE = 'male'
FEMALE = 'female'
OTHER = 'other'
SEX = [
(MALE, 'Male'),
(FEMALE, 'Female'),
(OTHER, 'Other'),
]
user = models.OneToOneField(User, on_delete=models.CASCADE)
phone_regex = RegexValidator(regex=r'^\d11$', message="Phone number must be entered in the format: '09151234567'.")
phone_number = models.CharField(validators=[phone_regex], max_length=11, blank=True)
middle_name = models.CharField(max_length=20, blank=True)
sex = models.CharField(max_length=6, choices=SEX, blank=True)
suffix = models.CharField(max_length=3, choices=GENERATIONAL_SUFFIX, blank=True)
birthday = models.DateField(null=True, blank=True)
hire_date = models.DateField(null=True, blank=True)
image = models.ImageField(blank=True, default='blank_profile_picture.jpg')
slug = models.SlugField(max_length=60, blank=True, null=True)
updated = models.DateTimeField(auto_now=True)
@property
def get_full_name(self):
first_name = self.user.first_name
middle_name = self.middle_name
last_name = self.user.last_name
if middle_name is None:
full_name = f'first_name" "last_name'
return full_name
else:
full_name = f'first_name" "middle_name" "last_name'
return full_name
def save(self, *args, **kwargs):
self.slug = slugify(self.get_full_name)
super().save(*args, **kwargs)
def __str__(self):
return self.get_full_name
class EmployeePosition(models.Model):
employee = models.ForeignKey(Employee, related_name='employee_position', on_delete=models.CASCADE)
position = models.ForeignKey(Position, on_delete=models.CASCADE)
position_change_reason = models.ForeignKey(PositionChangeReason, on_delete=models.CASCADE, default='Hired As')
effective_date = models.DateField()
class Meta:
get_latest_by = 'effective_date'
def __str__(self):
return str(self.position)
这里是视图:
class EmployeeListView(LoginRequiredMixin, ListView):
model = Employee
context_object_name = "employee_list"
def get_queryset(self):
employee_list = Employee.objects.prefetch_related('employee_position').all()
return employee_list
和模板:
% for emp in employee_list %
<tr>
<td> emp.user.id </td>
<td><a href="% url 'corehr:profile' emp.slug %"> emp.get_full_name </a></td>
<td> emp.user.email </td>
<td> emp.phone_number </td>
<td> emp.hire_date|date:"M d, Y" </td>
% for pos in emp.employee_position.all %
<td> pos.position </td>
% endfor %
</tr>
% endfor %
这会以我想要的方式在表格中显示我需要的所有数据,除了显示多个值的位置。
【问题讨论】:
【参考方案1】:解决此问题的一种方法是使用Subquery
从相关的EmployeePosition
中获取最新的position
字段:
from django.db.models import OuterRef, Subquery
employee_positions = EmployeePosition.objects.filter(
employee=OuterRef('pk')
).order_by('-effective_date').values('position')
employee_list = Employee.objects.annotate(
latest_position=Subquery(employee_positions[:1])
).all()
然后在你的模板中,你可以使用latest_position
:
emp.latest_position
【讨论】:
这太棒了!感谢您分享你的知识。该表显示您的解决方案的职位 ID,因为 EmployeePosition 模型中的职位是 ForeignKey。我尝试了 emp.latest_position.position ,就像在其他情况下一样,但它没有显示相关字段的名称。我可以添加什么来显示相关模型的职位名称吗? 啊在这种情况下尝试将.values('position')
更改为.values('position__position')
,看看是否有效
太棒了!像魅力一样工作。我不能感谢你。我花了几天时间尝试这里和其他地方提供的解决方案。这是唯一有效的。
别担心!很高兴有帮助以上是关于如何使用 prefetch_related 获取 Django 相关模型中的最新位置的主要内容,如果未能解决你的问题,请参考以下文章
如何在 django rest 框架中的嵌套序列化器相关对象上使用 prefetch_related?
Django prefetch_related缓存不反映更改