1

注意:這不是真正需要獲取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_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 name版本號is not valid for model Instr_Version .錯誤,所以我不確定發生了什麼。

我最後一次嘗試是將sourceversion = VersionSerializer更改爲versions,這是相反的關係。這看起來不合邏輯,但我正處在那個我正在嘗試任何事情的地步。結果是:一個錯誤version_number不是一個有效的領域,這告訴我,我終於等到了VersionSerializer,所以我註釋掉最VersionSerializer字段只是爲了看看發生了什麼事,但是這不僅導致: "Validated_Versions":[{"id":9,"version":{}},{"id":10,"version":{}},{"id":12,"version":{}}]

回答

0

原來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,那我改變了屬性名),以及串行因此,這是更好的工作。請注意,在更新此模型後,我運行了makemigrationsmigrate,並使用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_usertimestamp字段,所以我仍然需要處理這個問題。當我得到它時,我會更新。