【问题标题】:Django Rest Framework - Translating external unique code to a internal id and vice versaDjango Rest Framework - 将外部唯一代码转换为内部 id,反之亦然
【发布时间】:2019-09-26 17:54:48
【问题描述】:

我正在构建一个 Rest Api,它读取和更新一个名为 Requirements 的模型。 我正在使用 ModelSerializer。 需求模型在材料模型上有一个外键。

问题是我的 api 用户不知道 Materials 的内部 id 他只知道材料唯一的代码。 现在的想法是,在 PUT 中,他将 material_code 传递给我,我设置了材料 ID,在 GET 中,他根据需求的材料外键接收了材料代码

我设法通过覆盖 validate 方法并声明使 PUT 工作: material_code = serializers.CharField(max_length=50);
这是帖子末尾提供的代码。请注意,这是一个非常复杂的完整代码的 sn-p。在完整代码中,Requirements 序列化器嵌套在另一个序列化器中,而另一个序列化器嵌套在另一个序列化器中。但我认为这与问题无关。

然后我设法通过在 material_code 字段中使用自定义源选项来使 GET 工作,其中源是我的需求模型上的一个属性。为此,必须将声明更改为:

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 不应该去一个内部值。一旦我设法设置了材料 ID,我就不需要它了。

我无法让 PUT 和 GET 同时工作。 GET 只能与 serializers.ReadOnlyField 和 PUT 与 serializers.CharField 一起使用。

将 PUT 与 serializers.ReadOnlyField 一起使用会生成异常类型:KeyError 异常值“material_code”。

将 GET 与 serializers.CharField 一起使用会生成异常类型:AttributeError 异常值:尝试在序列化程序 RequirementsSerializer 上获取字段 material_code 的值时出现 AttributeError。序列化程序字段可能命名不正确,并且与 Requirements 实例上的任何属性或键都不匹配。原始异常文本为:“Requirements”对象没有“material_code”属性。

也许整个方法都是错误的。 我需要的是外部可见代码和内部 id 之间的转换。 这不应该那么难。这是我的第一个 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

【问题讨论】:

    标签: django django-rest-framework


    【解决方案1】:

    如果我理解正确,您希望用户能够使用材料代码作为材料的标识符(而不是 ID)来执行 PUT,并且您希望 GET 具有相同的行为称呼。如果是这种情况,我相信您正在寻找序列化程序的SlugRelatedField。示例:

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

    【讨论】:

    • 非常非常感谢。我没有足够的声誉投票,但你有我的感激之情。我希望答案比我的尝试容易得多。我不得不做一个小的调整。 material = serializers.SlugRelatedField(slug_field='code', queryset=Materials.objects.all())
    猜你喜欢
    • 1970-01-01
    • 2010-09-12
    • 1970-01-01
    • 1970-01-01
    • 2013-04-16
    • 1970-01-01
    • 2010-12-03
    • 2011-10-08
    • 2013-03-15
    相关资源
    最近更新 更多