【发布时间】: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