Django Rest Framework - перевод внешнего уникального кода во внутренний идентификатор и наоборот - PullRequest
1 голос
/ 26 сентября 2019

Я создаю Rest Api, который читает и обновляет модель под названием Requirements.Я использую ModelSerializer.Модель Requirements имеет внешний ключ для модели Materials.

Проблема в том, что мой пользователь API не знает внутренний идентификатор материалов. Он знает только код, уникальный для материала.Теперь идея состоит в том, что в PUT он передает мне код материала, и я устанавливаю идентификатор материала, а в GET он получает код материала, основанный на внешнем ключе материала Требований

. Мне удалось заставить работать PUT, переопределивметод проверки и объявления: material_code = serializers.CharField(max_length=50);
Это код, указанный в конце поста.Обратите внимание, что это фрагмент всего сложного кода.В полном коде сериализатор требований вложен в другой сериализатор, который вложен в другой сериализатор.Но я не думаю, что это имеет отношение к проблеме.

Тогда мне удается заставить GET работать, используя настраиваемую опцию источника в поле material_code, где источником является свойство в моей модели требований.Для этого объявление должно быть изменено на:

material_code = serializers.ReadOnlyField(source='get_material_code')

По некоторым причинам оба:

material_code = serializers.Field()

и

material_code = serializers.Field(source='get_material_code')

ведут себя странным образом и неработать либо с PUT, либо с GET, вызывая исключение «Field.to_internal_value () должно быть реализовано».Я попытался реализовать to_internal_value и попробовать, но не получилось.И в конце концов, material_code не должен переходить к внутреннему значению.Как только мне удалось установить идентификатор материала, он мне не нужен.

Нет способа заставить одновременно работать PUT и GET.GET будет работать только с сериализаторами. ReadOnlyField и PUT с сериализаторами. CharField.

Использование PUT с serializers.ReadOnlyField создает тип исключения: KeyError Значение исключения 'material_code'.

Использование GET с serializers.CharField создает тип исключения: AttributeError Значение исключения: Got AttributeError при попытке получить ошибкузначение для поля material_code на сериализаторе RequirementsSerializer.Поле сериализатора может иметь неправильное имя и не соответствовать ни одному атрибуту или ключу в экземпляре Requirements.Исходный текст исключения был: объект «Требования» не имеет атрибута «материал_код».

Возможно, весь подход неверен.Мне нужен перевод между внешне видимым кодом и внутренним идентификатором.Это не должно быть так сложно.Это мой первый проект на Python, и, возможно, есть встроенный способ заставить его работать в Django Rest Api, но я не смог найти его в документации.

Буду очень признателен за любую помощь.Кстати, это мой первый пост stackoverflow.Если я сделал что-то не так, пожалуйста, дайте мне знать.

class Materials (models.Model):
    class Meta:
        db_table = 'materials'
    code = models.CharField(max_length=50);
    full_name = models.CharField(max_length=50);

    def __str__(self):
        return self.full_name

class Requirements (models.Model):
    class Meta:
        db_table = 'requirements'
    material = models.ForeignKey(Materials, on_delete=models.CASCADE)
    acceptance_method = models.CharField(max_length=4)

    @property
    def get_material_code(self):
        return self.material.code


 class RequirementsSerializer(serializers.ModelSerializer):
    material_code = serializers.CharField(max_length=50);
    material = serializers.HiddenField(default=1)

    class Meta:
        model = Requirements
        fields = [  'id',
                    'material' ,
                    'material_code' ,
                    'acceptance_method'
        ]
        read_only_fields = ['material']


    def validate(self, data):
      # Fill material with a pk on Materials models
      # This is necessary since the API receive a material code instead of the model id
      if Materials.objects.filter(code = data['material_code']).exists() :
         data['material'] = Materials.objects.get(code = data['material_code'])
      else: 
         raise serializers.ValidationError('Material '+ data['material_code'] + ' does not exists')
      return data

1 Ответ

0 голосов
/ 26 сентября 2019

Если я правильно понимаю, вы хотите, чтобы пользователь мог сделать PUT, используя код материала в качестве идентификатора материала (вместо идентификатора), и вы хотите такое же поведение от GETвызов.Если это так, я думаю, что вы ищете SlugRelatedField сериализаторов.Пример:

class RequirementsSerializer(serializers.ModelSerializer):
    material = serializers.SlugRelatedField(slug_field='code')
...