【问题标题】:How to get latest position in Django's related model with prefetch_related如何使用 prefetch_related 获取 Django 相关模型中的最新位置
【发布时间】: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'^\d{11}$', 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 %}

这会以我想要的方式在表格中显示我需要的所有数据,除了显示多个值的位置。

【问题讨论】:

    标签: django django-models django-views django-templates django-queryset


    【解决方案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'),看看是否有效
    • 太棒了!像魅力一样工作。我不能感谢你。我花了几天时间尝试这里和其他地方提供的解决方案。这是唯一有效的。
    • 别担心!很高兴有帮助
    猜你喜欢
    • 2018-08-06
    • 2020-08-27
    • 2021-06-06
    • 2017-11-28
    • 2018-01-15
    • 2022-07-18
    • 2019-10-10
    • 2014-02-21
    • 1970-01-01
    相关资源
    最近更新 更多