【问题标题】:django drf serializer with a many-to-many model (with extra data)具有多对多模型的 django drf 序列化程序(带有额外数据)
【发布时间】:2017-03-22 06:35:45
【问题描述】:

注意:这并不是真正让 Django 的中间模型用于具有额外字段的多对多关系。这是关于如何将 Django Rest Framework 的 Serializers.ModelSerializer 与中间模型一起使用。 我有这些模型(以及更多):

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 可以检索被列为对该仪器有效的所有版本(及其 FK_method 数据,通过 MethodSerializer)的 json 表示。 到目前为止,我有这些序列化程序(还有一些用于 InstrType、UserProfile 等)

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": "0123456789ABCDEF0123",
    "instr_type": {
        "id": 70,
        "make": "Make1",
        "model": "Model1",
        "service_email": "model1@company.com",
        "service_website": "www.model1.com"
    },
    "Validated_Versions": [{
        "id": 9
    }, {
        "id": 10
    }, {
        "id": 12
    }]
}

这很不错,但是validated_versions 数组应该包含比“id”更多的数据。

为了实验,我尝试从Instr_to_VersionSerializerVersionSerializer 的字段列表中添加/删除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 nameversion_numberis not valid for modelInstr_Version. 错误,所以我不确定发生了什么。

我自己的最后一次尝试是将version = VersionSerializersource 更改为versions,这是相反的关系。这似乎不合逻辑,但我当时正在尝试任何事情。结果是:version_number 不是有效字段的错误,这告诉我我终于到达了VersionSerializer,所以我注释掉了VersionSerializer 中的大部分字段,只是为了看看发生了什么,但这只是导致: "Validated_Versions":[{"id":9,"version":{}},{"id":10,"version":{}},{"id":12,"version":{}}]

【问题讨论】:

    标签: django rest serialization django-rest-framework many-to-many


    【解决方案1】:

    原来related_nameInstrumentsInstr_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,并且我更改了属性名称),以及相应的序列化程序,这会更好。请注意,在更新此模型后,我使用manage.py 运行了makemigrationsmigrate,然后它就可以工作了。新结果是:

    {
        "id": 11,
        "asset_number": "1234",
        "serial_number": "1234",
        "name": "Instrument1",
        "checksum_string": "0123456789ABCDEF0123",
        "instr_type": {
            "id": 70,
            "make": "Make1",
            "model": "Model1",
            "service_email": "model1@company.com",
            "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')
    

    特别注意InstrumentSerializerValidated_Versions =

    我缺少的一件事是我真的很想在结果中看到Instr_Version 模型上的validating_usertimestamp 字段,所以我仍然需要努力。我会在它工作时更新。

    【讨论】:

      猜你喜欢
      • 2022-06-25
      • 1970-01-01
      • 1970-01-01
      • 2017-06-18
      • 1970-01-01
      • 2019-07-22
      • 2017-10-30
      • 1970-01-01
      • 2021-03-11
      相关资源
      最近更新 更多