带有多对多模型的django drf序列化程序(带额外数据)
注意:这不是真正需要获取Django的中间模型,以实现与多余字段一起工作的多对多关系。这是关于如何使用Django Rest Framework的Serializers.ModelSerializer与中间模型。 我有这些模型(和更多):带有多对多模型的django drf序列化程序(带额外数据)
class Method(models.Model):
name = models.CharField(max_length=50, unique=True)
descripton = models.TextField(null=False)
class Version(models.Model):
version_number = models.CharField(max_length=50)
cmd_line_script = models.CharField(max_length=250, null=False)
SOP = models.TextField(null=False)
FK_method = models.ForeignKey(Method, on_delete=models.CASCADE)
class Meta:
unique_together = ('version_number', 'FK_method')
class Instrument(models.Model):
serial_number = models.CharField(max_length=50, unique=True)
asset_number = models.CharField(max_length=50, unique=True)
name = models.CharField(max_length=50)
checksum_string = models.CharField(max_length=128, null=True)
FK_instr_type = models.ForeignKey(InstrType, related_name='installations', on_delete=models.PROTECT)
Instr_Version = models.ManyToManyField(
Version,
through='Instr_Version',
related_name = 'Instr_Version',
)
class Instr_Version(models.Model):
FK_version = models.ForeignKey(Version, on_delete=models.CASCADE)
FK_instrument = models.ForeignKey(Instrument, on_delete=models.CASCADE)
validating_user = models.ForeignKey(UserProfile, on_delete=models.PROTECT)
timestamp = models.DateField(auto_now_add=True)
class Meta:
unique_together = ('FK_version', 'FK_instrument')
他们很好。我试图使用[Django-Rest-Framework serializers][1]
通过Instr_Version表进行序列化,因此api可以检索所有版本的JSON表示(以及它们的FK_method数据,通过MethodSerializer),这些表示对该工具有效。 我有这些串行到目前为止(和一对夫妇更多的InstrType,用户配置等)
class MethodSerializer(serializers.ModelSerializer):
class Meta:
model = Method
fields = ('id', 'name', 'description', 'version_set')
class VersionSerializer(serializers.ModelSerializer):
method = MethodSerializer(read_only=True)
#Instr_Version = Instr_VersionSerializer(source='Instr_Version_set', many=True, read_only=True)
class Meta:
model = Version
fields = ('id', 'method', 'version_number', 'cmd_line_script', 'SOP')
class Instr_to_VersionSerializer(serializers.ModelSerializer):
version = VersionSerializer(source='FK_version_id', read_only=True, many=False)
validator = UserProfileSerializer(source='validating_user', read_only=True)
class Meta:
model = Instr_Version
fields = ('id', 'version', 'validator', 'timestamp')
class InstrumentSerializer(serializers.ModelSerializer):
instr_type = InstrTypeSerializer(source='FK_instr_type', read_only=True)
Validated_Versions = Instr_to_VersionSerializer(source='Instr_Version', many=True, read_only=True)
class Meta:
model = Instrument
fields = ('id', 'asset_number', 'serial_number', 'name', 'checksum_string', 'instr_type', 'Validated_Versions')
我已经得到的最接近的是,像一个GET: “API/getInstrument/asset_number = 1234?” 结果在:
{
"id": 11,
"asset_number": "1234",
"serial_number": "1234",
"name": "Instrument1",
"checksum_string": "ABCDEF0123",
"instr_type": {
"id": 70,
"make": "Make1",
"model": "Model1",
"service_email": "[email protected]",
"service_website": "www.model1.com"
},
"Validated_Versions": [{
"id": 9
}, {
"id": 10
}, {
"id": 12
}]
}
这是相当不错的,但validated_versions数组应该比'id'有更多的数据。
为了实验的缘故,我尝试在Instr_to_VersionSerializer
和VersionSerializer
的字段列表中添加/删除id
。证据表明,Instr_to_VersionSerializer
内的字段列表中的id
实际上是在Instr_Version
模型(或版本模型上的PK)上打印FK_version_id
,而不是像我所预期的Instr_Version
的PK。这使我想到,DJR是“自动”通过多到多,直奔Version
模型,所以我试图改变Instr_to_VersionSerializer
看到:
class Instr_to_VersionSerializer(serializers.ModelSerializer):
#version = VersionSerializer(source='FK_version_id', read_only=True, many=False)
validator = UserProfileSerializer(source='validating_user', read_only=True)
#method = MethodSerializer(read_only=True)
class Meta:
model = Instr_Version
fields = ('id', 'version_number', 'cmd_line_script', 'SOP', 'validator', 'timestamp')
这将离开VersionSerializer出来的全部,但我收到Field name
版本号is not valid for model
Instr_Version .
错误,所以我不确定发生了什么。
我最后一次尝试是将source
的version = VersionSerializer
更改为versions
,这是相反的关系。这看起来不合逻辑,但我正处在那个我正在尝试任何事情的地步。结果是:一个错误version_number
不是一个有效的领域,这告诉我,我终于等到了VersionSerializer
,所以我注释掉最VersionSerializer
字段只是为了看看发生了什么事,但是这不仅导致: "Validated_Versions":[{"id":9,"version":{}},{"id":10,"version":{}},{"id":12,"version":{}}]
原来related_name
为Instruments
和Instr_Version
之间的关系导致了问题。我更新了模型:
class Instrument(models.Model):
serial_number = models.CharField(max_length=50, unique=True)
asset_number = models.CharField(max_length=50, unique=True)
name = models.CharField(max_length=50)
checksum_string = models.CharField(max_length=128, null=True)
FK_instr_type = models.ForeignKey(InstrType, related_name='installations', on_delete=models.PROTECT)
VersionsFromInstrument = models.ManyToManyField(
Version,
through='Instr_Version',
related_name = 'InstrumentsFromVersion',
)
(请注意:最后一个属性的新related_name,那我改变了属性名),以及串行因此,这是更好的工作。请注意,在更新此模型后,我运行了makemigrations
和migrate
,并使用manage.py
,然后运行。新的结果是:
{
"id": 11,
"asset_number": "1234",
"serial_number": "1234",
"name": "Instrument1",
"checksum_string": "ABCDEF0123",
"instr_type": {
"id": 70,
"make": "Make1",
"model": "Model1",
"service_email": "[email protected]",
"service_website": "www.model1.com"
},
"Validated_Versions": [{
"id": 9,
"method": {
"id": 9,
"name": "Method1",
"description": "method one description",
"version_set": [11, 9]
},
"version_name": "123",
"cmd_line_script": "script",
"SOP": "SOP"
}, {
"id": 10,
"method": {
"id": 10,
"name": "Method2",
"description": "method two description",
"version_set": [12, 10]
},
"version_name": "123",
"cmd_line_script": "script",
"SOP": "SOP"
}, {
"id": 12,
"method": {
"id": 10,
"name": "Method2",
"description": "method two description",
"version_set": [12, 10]
},
"version_name": "456",
"cmd_line_script": "script",
"SOP": "SOP"
}]
}
的情况下,它是帮助他人在未来,这是我更新Serilaizers与变化模型关联:
class MethodSerializer(serializers.ModelSerializer):
description = serializers.ReadOnlyField(source='descripton')
class Meta:
model = Method
fields = ('id', 'name', 'description', 'version_set')
class VersionSerializer(serializers.ModelSerializer):
method = MethodSerializer(read_only=True)
#Instr_Version = Instr_VersionSerializer(source='Instr_Version_set', many=True, read_only=True)
class Meta:
model = Version
fields = ('id', 'method')#, 'version_number', 'cmd_line_script', 'SOP')
class Instr_to_VersionSerializer(serializers.ModelSerializer):
version = VersionSerializer(source='FK_version', read_only=True, many=True)
validator = UserProfileSerializer(source='validating_user', read_only=True)
version_name = serializers.ReadOnlyField(source='version_number')
cmd_line_script = serializers.ReadOnlyField()
SOP = serializers.ReadOnlyField()
method = MethodSerializer(source='FK_method',read_only=True)
class Meta:
model = Instr_Version
fields = ('id', 'version', 'validator', 'timestamp', 'method', 'version_name', 'cmd_line_script', 'SOP')
class InstrumentSerializer(serializers.ModelSerializer):
instr_type = InstrTypeSerializer(source='FK_instr_type', read_only=True)
Validated_Versions = Instr_to_VersionSerializer(source='VersionsFromInstrument', many=True, read_only=True)
class Meta:
model = Instrument
fields = ('id', 'asset_number', 'serial_number', 'name', 'checksum_string', 'instr_type', 'Validated_Versions')
特别要注意Validated_Versions =
线的InstrumentSerializer
我失踪的一件事是,我真的很想在结果中看到Instr_Version
模型上的validating_user
和timestamp
字段,所以我仍然需要处理这个问题。当我得到它时,我会更新。