1

HINWEIS: Es geht nicht wirklich darum, Djangos Zwischenmodell für die Viele-zu-Viele-Beziehung mit zusätzlichen Feldern zu erhalten. Hier erfahren Sie, wie Sie den Serializers.ModelSerializer von Django Rest Framework mit einem Zwischenmodell verwenden. Ich habe diese Modelle (und mehr):django drf Serializer mit einem Viele-zu-Viele-Modell (mit zusätzlichen Daten)

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') 

und sie sind in Ordnung. Ich versuche die [Django-Rest-Framework serializers][1] zu verwenden, um durch die Instr_Version-Tabelle zu serialisieren, so dass eine API eine JSON-Darstellung aller Versionen (und ihrer FK_method-Daten über einen MethodSerializer) abrufen kann, die für dieses Instrument als gültig aufgeführt sind. Ich habe diesen Serializer bisher (und ein paar mehr für InstrType, Userprofile, etc.)

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') 

Die nächstgelegene ich bekommen habe, ist, dass ein GET wie: "api/getInstrument/asset_number = 1234?" Ergebnisse in:

{ 
    "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 
    }] 
} 

was ziemlich gut ist, aber die validated_versions Array viel mehr Daten als nur ein ‚id‘ haben sollte.

Ich habe versucht, die id aus der Liste der Felder in Instr_to_VersionSerializer und VersionSerializer für das Experiment hinzufügen/entfernen. Beweise besagt, dass die id in der Liste der Felder innerhalb Instr_to_VersionSerializer ist tatsächlich Drucken der FK_version_id auf dem Instr_Version Modell (oder der PK auf dem Version-Modell), nicht die PK Instr_Version wie ich erwartet hatte. Das machte mich denken, dass DJR ‚automatisch‘ war die many-to-many sehen durch, direkt zum Version Modell, so habe ich versucht Instr_to_VersionSerializer an veränderte:

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') 

, die die VersionSerializer aus ihm völlig verlassen würde, aber Ich bekomme eine Field name Versionsnummer is not valid for model Instr_Version . Fehler, so dass ich nicht sicher bin, was los ist.

Ein letzter Versuch selbst war, die source für die version = VersionSerializer zu versions zu ändern, die die umgekehrte Beziehung ist. das schien unlogisch, aber ich bin an dem Punkt, wo ich alles versuche. Ergebnis war: ein Fehler, dass version_number war kein gültiges Feld, die mir sagte, dass ich schließlich auf die VersionSerializer bekommen, so kommentierte ich die meisten Felder in VersionSerializer heraus nur um zu sehen, was los war, aber dies nur führte zu: "Validated_Versions":[{"id":9,"version":{}},{"id":10,"version":{}},{"id":12,"version":{}}]

Antwort

0

Es stellt sich heraus, related_name für die Beziehung zwischen Instruments und Instr_Version wurde das Problem verursacht. Ich aktualisiert das Modell:

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', 
        ) 

(Beachten Sie die neue related_name am letzten Attribut, und dass ich das Attribut Name geändert), und die Serializer entsprechend und das funktioniert besser. Hinweis Ich lief makemigrations und migrate mit manage.py nach der Aktualisierung dieses Modells, dann funktioniert es.Neues Ergebnis ist:

{ 
    "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" 
    }] 
} 

, falls andere in der Zukunft ist es hilfreich, mein aktualisiert Serilaizers hier ist mit den Änderungen Modell zu korrelieren:

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') 

Besonders beachten Sie die Validated_Versions = Linie der InstrumentSerializer

Eine Sache, die ich vermisse ist, dass ich wirklich die validating_user und timestamp Felder auf dem Instr_Version Modell im Ergebnis sehen möchte, also muss ich noch daran arbeiten. Ich werde aktualisieren, wenn es funktioniert.

Verwandte Themen