#django #django-models #django-views #django-templates #django-queryset
Вопрос:
Я пытался получить последнее повышение сотрудника на основе даты вступления в силу модели должности сотрудника, которая имеет отношение «многие к одному» и модель сотрудника.
Основываясь на своем исследовании, я нашел способ предварительной обработки данных, но я получаю несколько результатов, поскольку не могу понять, как фильтровать наши значения с даты вступления в силу.
Вот модели:
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}
Вот такой вид:
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
для получения последнего position
поля из соответствующего EmployeePosition
:
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 }}
Комментарии:
1. Это просто замечательно! Спасибо вам за то, что поделились своими знаниями. В таблице отображается идентификатор позиции с вашим решением, так как позиция в модели должности сотрудника-это внешний ключ. Я попробовал emp.latest_position.position, как и в других случаях, но он не отображает имя из связанного поля. Есть ли что-нибудь, что я могу добавить для отображения названия должности из связанной модели?
2. Ах, в таком случае попробуйте переключиться
.values('position')
на.values('position__position')
и посмотрите, работает ли это3. Замечательно! сработало как заклинание. Я не могу отблагодарить тебя как следует. Я потратил дни, пробуя решения, предлагаемые здесь и в других местах. Это единственное, что сработало.
4. Не беспокойтесь! Рад, что помог
, 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)
Вот такой вид:
и шаблон:
Это отображает все необходимые мне данные в таблице так, как я хочу, за исключением позиции, которая отображает несколько значений.
Ответ №1:
Один из способов решить эту проблему-использовать Subquery
для получения последнего position
поля из соответствующего EmployeePosition
:
А затем в своем шаблоне вы можете использовать latest_position
:
Комментарии:
1. Это просто замечательно! Спасибо вам за то, что поделились своими знаниями. В таблице отображается идентификатор позиции с вашим решением, так как позиция в модели должности сотрудника-это внешний ключ. Я попробовал emp.latest_position.position, как и в других случаях, но он не отображает имя из связанного поля. Есть ли что-нибудь, что я могу добавить для отображения названия должности из связанной модели?
2. Ах, в таком случае попробуйте переключиться
.values('position')
на.values('position__position')
и посмотрите, работает ли это3. Замечательно! сработало как заклинание. Я не могу отблагодарить тебя как следует. Я потратил дни, пробуя решения, предлагаемые здесь и в других местах. Это единственное, что сработало.
4. Не беспокойтесь! Рад, что помог