Как сериализовать несколько моделей в один сериализатор для иерархической структуры с помощью Django Rest Framework? - PullRequest
0 голосов
/ 12 апреля 2019

У меня есть четыре модели, где мне нужно сериализовать три в одну для моего API. Я могу заставить отдельные сериализаторы работать как положено, но при объединении их в один я не получаю ожидаемого результата.

models.py

class President(models.Model):
    name = models.CharField('Name', max_length=50,)
    staff = models.ManyToManyField('Member',)
    def __str__(self):
        return self.name

"""
user creates a new member in this model below
if a new member is an employee, the object is copied into the Employee model
    and the user chooses the manager of the employee in the manager field
if a new member is a manager, the object is copied into the Manager model
"""
class Member(models.Model):
    president = models.ForeignKey(
        President, on_delete=models.CASCADE, related_name='members',
    )
    manager = models.ForeignKey(
        'Manager', on_delete=models.CASCADE, related_name='manager',
    )
    name = models.CharField('Name', max_length=50,)
    email = models.EmailField('Email Address',)
    title = models.CharField('Title', max_length=50,)
    staff_type = (
        ('Manager', 'Manager'),
        ('Employee', 'Employee'),
    )
    def __str__(self):
        return self.name

class Employee(models.Model):
    president = models.ForeignKey(
        President, on_delete=models.CASCADE, related_name='employeePresident'
    )
    manager = models.ForeignKey(
        'Manager', on_delete=models.CASCADE, related_name='employeeManager'
    )
    name = models.CharField('Name', max_length=50,)
    email = models.EmailField('Email Address',)
    title = models.CharField('Title', max_length=50,)
    def __str__(self):
        return self.name

class Manager(models.Model):
    president = models.ForeignKey(
        President, on_delete=models.CASCADE, related_name='managerPresident'
    )
    name = models.CharField('Name', max_length=50,)
    department = models.CharField('Department', max_length=50,)
    def __str__(self):
        return self.name

serializers.py

class PresidentSerializer(serializers.ModelSerializer):
    class Meta:
        model = President
        fields = '__all__'
class EmployeeSerializer(serializers.ModelSerializer):
    class Meta:
        model = Employee
        fields = '__all__'
class ManagerSerializer(serializers.ModelSerializer):
    members = EmployeeSerializer(many=True,)
    class Meta:
        model = Manager
        fields = ('president', 'name', 'department', 'members')

До этого момента все эти сериализаторы работали как положено. ManagerSerializer отображает имя менеджера и сотрудников под ними в виде дерева, как я хочу.

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

Как мне объединить эти три сериализатора в один, где мой API будет выглядеть следующим образом:

{
    "name": "Presidents Name",
    "staff": [
        {
            "name": "Employee No Manager",
            "title": "Presidents Asst"
        },
        {
            "name": "John Doe",
            "title": "Finance Manager",
            "employees": [
                {
                    "name": "Mary Simpson",
                    "title": "Finance Asst"
                }
            ]
        }
}

Не уверен, что что-то должно измениться в моей модели, где модель President может использоваться как в модели Employee, так и в Manager. Любая помощь будет принята с благодарностью.

1 Ответ

0 голосов
/ 12 апреля 2019

Я бы упростил вашу структуру БД до 1 класса для каждого сотрудника (и 2 дополнительных класса для нормализации БД):

class JobTitle(models.Model):
    title = models.CharField('Title', max_length=50)

    def __str__(self):
        return self.title


class Department(models.Model):
    name = models.CharField('Department', max_length=50)

    def __str__(self):
        return self.name


class Employee(models.Model):
    name = models.CharField('Name', max_length=50)
    boss = models.ForeignKey("Employee", on_delete=models.CASCADE, related_name="staff", blank=True, null=True)
    department = models.ForeignKey("Department", on_delete=models.CASCADE)
    email = models.EmailField('Email Address')
    title = models.ForeignKey("JobTitle", on_delete=models.CASCADE)

    @property
    def is_president(self):
        return self.boss is None

    @property
    def is_manager(self):
        return len(self.staff) > 0

    def __str__(self):
        return self.name

Тогда вы можете использовать рекурсивный сериализатор из этот ответ :

class RecursiveField(serializers.Serializer):
    def to_representation(self, value):
        serializer = self.parent.parent.__class__(value, context=self.context)
        return serializer.data

class EmployeeSerializer(serializers.ModelSerializer):
    staff = RecursiveField(many=True)

    class Meta:
        model = Employee
        fields = '__all__'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...