Переопределить обязательное поле в валидаторе django DRF - PullRequest
0 голосов
/ 03 апреля 2020

У меня есть простые модели EmployeeSkill и Skill:


class EmployeeSkill(models.Model):

    # this is required
    employee = models.ForeignKey(
        Employee, on_delete=models.CASCADE
    )

    # this is required
    skill = models.ForeignKey(
        Skill, on_delete=models.CASCADE
    )

    def skill_name(self):
        return self.skill.name


class Skill(models.Model):

    # this is required
    name = models.CharField(max_length=255, unique=True)

Я хочу сохранить атрибут навыка EmployeeSkill, необходимый для модели, но я хочу включить передачу только имени навыка в сериализаторе, что получить или создать соответствующий навык. Вот мой сериализатор:


class EmployeeSkillSerializer(serializers.ModelSerializer):

    class Meta:
        fields = (
            "id",
            "employee",
            "skill",
            "skill_name",
        )
        model = EmployeeSkill
        extra_kwargs = {
            "skill": {"required": False},
        }


    def validate_skill(self, value):
        """ custom validator for skill. skill can be empty if skill_name is valid """

        if value is None:
            skill_name = getattr(self, "skill_name", None)
            if not (skill_name and type(skill_name) is str):
                raise serializers.ValidationError(
                    "if no skill is provided, skill_name should be a valid string"
                )

        elif not type(value) is Skill:
            raise serializers.ValidationError("skill must be of type Skill or None")

        return value


    def create(self, validated_data):
        if (not self.skill) and self.skill_name:
            validated_data["skill"] = Skill.objects.get_or_create(skill_name=self.skill_name)[0]
        super().create(validated_data)

Проблема в том, что я все еще получаю сообщение об ошибке:

{
    "skill": [
        "This field may not be null."
    ],
}

Есть идеи о том, как я могу решить мою проблему?

Ответы [ 2 ]

1 голос
/ 03 апреля 2020

Простое лучше, чем сложное:

class EmployeeSkillSerializer(serializers.ModelSerializer):
    <b>skill = serializers.CharField(source='skill.name')</b>

    class Meta:
        fields = ("id", "employee", "skill")
        model = EmployeeSkill

    <b>def create(self, validated_data):
        skill_name = validated_data.pop('skill', {}).get('name', '')
        skill_instance, created = Skill.objects.get_or_create(name=skill_name)
        validated_data['skill'] = skill_instance
        return super().create(validated_data)</b>

Пример JSON полезная нагрузка,

{
    "employee": "Martin Faucheux",
    "skill": "Programming"
}
1 голос
/ 03 апреля 2020

Я немного изменил функцию создания. Также добавлено поле skill_name в сериализаторе.

from rest_framework import serializers
from webtest.models import EmployeeSkill, Skill


class EmployeeSkillSerializer(serializers.ModelSerializer):
    skill_name = serializers.CharField()

    class Meta:
        fields = (
            "id",
            "employee",
            "skill",
            "skill_name",
        )
        model = EmployeeSkill
        extra_kwargs = {
            "skill": {"required": False},
        }


    def validate_skill(self, value):
        """ custom validator for skill. skill can be empty if skill_name is valid """

        if value is None:
            skill_name = getattr(self, "skill_name", None)
            if not (skill_name and type(skill_name) is str):
                raise serializers.ValidationError(
                    "if no skill is provided, skill_name should be a valid string"
                )

        elif not type(value) is Skill:
            raise serializers.ValidationError("skill must be of type Skill or None")

        return value


    def create(self, validated_data):
        if not validated_data.get('skill') and validated_data.get('skill_name'):
            validated_data["skill"] = Skill.objects.get_or_create(name=validated_data['skill_name'])[0]
        if 'skill_name' in validated_data:
            del validated_data['skill_name']
        return super().create(validated_data)
...