Python Django Rest - вернуть дополнительное поле с самым низким, самым высоким и средним значениями какого-либо другого поля

Я новичок в Django и API в целом, и я хочу создать API на основе Django с использованием Django Rest Framework.

Вот что я хочу сделать:

От конечной точки до отчета по возрастному диапазону:

curl -H 'Content-Type: application/json' localhost:8000/reports/employees/age/

Ответ:

{
    "younger": {
        "id": "1",
        "name": "Anakin Skywalker",
        "email": "skywalker@ssys.com.br",
        "department": "Architecture",
        "salary": "4000.00",
        "birth_date": "01-01-1983"},
    "older": {
        "id": "2",
        "name": "Obi-Wan Kenobi",
        "email": "kenobi@ssys.com.br",
        "department": "Back-End",
        "salary": "3000.00",
        "birth_date": "01-01-1977"},
    "average": "40.00"
}

От конечной точки к отчету о диапазоне зарплат:

curl -H 'Content-Type: application/json' localhost:8000/reports/employees/salary/

Ответ:

{
    "lowest ": {
        "id": "2",
        "name": "Obi-Wan Kenobi",
        "email": "kenobi@ssys.com.br",
        "department": "Back-End",
        "salary": "3000.00",
        "birth_date": "01-01-1977"},
    "highest": {
        "id": "3",
        "name": "Leia Organa",
        "email": "organa@ssys.com.br",
        "department": "DevOps",
        "salary": "5000.00",
        "birth_date": "01-01-1980"},
    "average": "4000.00"
}

У меня есть два приложения, employees и reports.

Вот сотрудники/models.py:

class Employee(models.Model):
    name = models.CharField(max_length=250, default='FirstName LastName')
    email = models.EmailField(max_length=250, default='employee@email.com')
    departament = models.CharField(max_length=250, default='Full-Stack')
    salary = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    birth_date = models.DateField()

Вот сотрудники/serializers.py:

class EmployeeSerializer(serializers.ModelSerializer):
    class Meta:
        model = Employee
        fields = ['id', 'name', 'email', 'departament', 'salary', 'birth_date']

Я не знаю, как создавать представления и сериализаторы для своего приложения для отчетов. Как мне подойти к этому?

Как я могу вернуть дополнительное поле с расчетом между значениями другого поля? Должен ли я создать настраиваемое поле в моем сериализаторе?

Прочитав документы, я понял, что запрос, который я должен использовать, должен выглядеть примерно так:

Employee.objects.aggregate(Max("salary"), Min("salary"), Avg("salary"))

Или, например, для зарплаты:

Employee.objects.all().order_by('salary')

Но как мне его использовать?

Я не знаю, где это использовать и как это сделать, поскольку мое понимание API и Django Rest Framework все еще очень слабое.

Должен ли он идти в моем отчеты/view.py? Или в моем сотрудники/serializers.py?

Должен ли я создать файл отчеты/serializers.py?

Нужен ли мне класс отчеты/модель с полями lowest, highest, average плюс поле объекта сотрудника?

Должен ли я переопределить функцию list() моего класса ReportSalaryListAPIView в моем отчеты/views.py? (Этот класс еще не существует)

Я очень потерян и сбит с толку. Пожалуйста, помогите указать мне правильное направление.

Заранее спасибо.


Редактировать:

Мой сотрудники /model.py теперь выглядит так:

class Employee(models.Model):
    name = models.CharField(max_length=250, default='FirstName LastName')
    email = models.EmailField(max_length=250, default='employee@email.com')
    departament = models.CharField(max_length=250, default='Full-Stack')
    salary = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    birth_date = models.DateField()

    @property
    def get_age(self):
        delta = relativedelta(self.birth_date.days, datetime.today()).years
        return delta

    def save(self, *args, **kwargs):
        self.age = self.get_age()
        super(Employee, self).save(*args, **kwargs)

Мой сотрудники/serializers.py сейчас:

class EmployeeSerializer(serializers.ModelSerializer):

    class Meta:
        model = Employee
        fields = ['id', 'name', 'email', 'departament', 'salary', 'birth_date', 'age']

На всякий случай я запустил команды makemigrations и migrate с manager.py.

Но теперь я сталкиваюсь с этой ошибкой при попытке создать нового сотрудника:

'datetime.date' object has no attribute 'days'

Что происходит?

Анализ настроения постов в Twitter с помощью Python, Tweepy и Flair
Анализ настроения постов в Twitter с помощью Python, Tweepy и Flair
Анализ настроения текстовых сообщений может быть настолько сложным или простым, насколько вы его сделаете. Как и в любом ML-проекте, вы можете выбрать...
7 лайфхаков для начинающих Python-программистов
7 лайфхаков для начинающих Python-программистов
В этой статье мы расскажем о хитростях и советах по Python, которые должны быть известны разработчику Python.
Установка Apache Cassandra на Mac OS
Установка Apache Cassandra на Mac OS
Это краткое руководство по установке Apache Cassandra.
Сертификатная программа "Кванты Python": Бэктестер ансамблевых методов на основе ООП
Сертификатная программа "Кванты Python": Бэктестер ансамблевых методов на основе ООП
В одном из недавних постов я рассказал о том, как я использую навыки количественных исследований, которые я совершенствую в рамках программы TPQ...
Создание персонального файлового хранилища
Создание персонального файлового хранилища
Вы когда-нибудь хотели поделиться с кем-то файлом, но он содержал конфиденциальную информацию? Многие думают, что электронная почта безопасна, но это...
Создание приборной панели для анализа данных на GCP - часть I
Создание приборной панели для анализа данных на GCP - часть I
Недавно я столкнулся с интересной бизнес-задачей - визуализацией сбоев в цепочке поставок лекарств, которую могут просматривать врачи и...
0
0
36
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Идея

Никаких дополнительных полей для хранения рассчитанных значений не требуется, поскольку они вычисляются на основе строк в базе данных.

  1. Сначала вы находите min_salary, max_salary и avg_salary, используя метод агрегата.
  2. Используйте найденные min_salary и max_salary, чтобы найти сотрудников.
  3. Реализуйте класс сериализатора, который сериализует highest, lowest и average отчет о зарплате сотрудников.
  4. Сериализуйте lowest, highest и avarage с помощью реализованного класса сериализатора.

Код

На мой взгляд, код для выполнения логики должен быть на другом уровне, обычно называемом сервисным.

# employees/services.py
class EmployeeSalaryReport:
    def __init__(self, lowest, highest, average):
        self.lowest = lowest
        self.highest = highest
        self.average = average

def get_employee_salary_report():
    salary_report_dict = Employee.objects.aggregate(
        min_salary=Min("salary"),
        max_salary=Max("salary"),
        avg_salary=Avg("salary"),
    )
    lowest_salary_employee = Employee.objects.filter(
        salary=salary_report_dict.get("min_salary")
    ).first()
    highest_salary_employee = Employee.objects.filter(
        salary=salary_report_dict.get("max_salary")
    ).first()
    return EmployeeSalaryReport(
        lowest=lowest_salary_employee,
        highest=highest_salary_employee,
        average=salary_report_dict.get("avg_salary"),
    )
# employees/serializers.py
class EmployeeSalaryReportSerializer(serializers.Serializer):
    lowest = EmployeeSerializer()
    highest = EmployeeSerializer()
    average = serializers.FloatField()
# employees/views.py
from rest_framework import views
from rest_framework.response import Response

from employees.services import get_employee_salary_report
from employees.serializers import EmployeeSalaryReportSerializer


class ReportSalaryView(views.APIView):
    def get(self, request, *args, **kwargs):
        employee_salary_report = get_employee_salary_report()
        serializer = EmployeeSalaryReportSerializer(employee_salary_report)
        return Response(serializer.data)
# employees/urls.py
from django.urls import path

from employees.views import ReportSalaryView


urlpatterns = [
    ...  # other paths
    path("reports/employees/salary/", ReportSalaryView.as_view(), name="report-salary"),
]

Это сработало отлично. Спасибо. Сейчас я пытаюсь сделать отчет о возрасте: пока я создал вычисляемое поле в своем файле сотрудники /model.py для расчета возраста. Затем я переопределил метод save(), чтобы включить self.age = self.get_age(). Но теперь я борюсь с ошибкой, которая говорит 'datetime.date' object has no attribute 'days'. Я отредактировал вопрос, включив в него мою собственность get_age. Не могли бы вы взглянуть и сказать мне, что не так? Большое тебе спасибо :)

Laila Campos 17.05.2022 22:05

Не обращайте внимания на мой последний комментарий. Я решил создать метод get_age внутри своего EmployeeSerializer, и это решило проблему. Отмечаю вопрос как решенный. Большое тебе спасибо.

Laila Campos 18.05.2022 02:12

Другие вопросы по теме