webentwicklung-frage-antwort-db.com.de

Fügen Sie einem ModelSerializer in DRF 3 ein Nichtmodellfeld hinzu

Wie füge ich ein Nichtmodellfeld in einem ModelSerializer in DRF 3 hinzu? d.h. ein Feld hinzufügen, das in meinem tatsächlichen Modell nicht vorhanden ist?

class TestSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='vote_detail')
    non_field = serializers.CharField()  # no corresponding model property.


    class Meta:
        model = vote_model
        fields = ("url", "non_field")

    def create(self, validated_data):
      print(direction=validated_data['non_field'])

Aber DRF 3 gibt mir den Fehler:

Got AttributeError when attempting to get a value for field `non_field` on serializer `TestSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Test` instance.
Original exception text was: 'Test' object has no attribute 'non_field'.

Ich habe nach Stack DRF - ModelSerializer mit einem Nicht-Modell-Feld write_only gesucht und einige Lösungen gefunden, die sich jedoch auf DRF 2 beziehen, in dem ich DRF 3 verwende. Gibt es für diese Version eine Lösung?

33
Prometheus
class TestSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='vote_detail')
    non_field = serializers.SerializerMethodField()  # no corresponding model property.

    class Meta:
        model = vote_model
        fields = ("url", "non_field")

    def create(self, validated_data):
        print(direction=validated_data['non_field'])

http://www.Django-rest-framework.org/api-guide/fields/#serializermethodfield

oder gehen Sie diese Link

4
chandu
class MySerializer(serializers.ModelSerializer):
    write_only_char_field = serializer.CharField(write_only=True)
    write_only_list_char_field = serializer.ListField(child=serializers.CharField(max_length=100, default=''), write_only=True)
    empty_method_field = serializers.SerializerMethodField()
    read_only_custom_model_field = serializers.CharField(source='custom_property', read_only=True)

    def create(self, validated_data):
        validated_data.pop('write_only_char_field', None)
        validated_data.pop('write_only_list_char_field', None)
        return super().create(validated_data)

Die serializers.CharField(write_only=True) und serializers.ListField(...) sind eine gute Lösung, um Ihren .create Und .update Methoden zusätzliche Daten als einzelne Zeichenfolge oder als Liste von bereitzustellen Zeichenfolgen (Sie können ListField mit anderen Serializer-Feldtypen mischen). Mit dieser Methode können Sie auch def validate_write_only_char_field Definieren, um eine schnelle und einfache Validierung zu implementieren.

Mit serializers.SerializerMethodField() können Sie Ihrer Serializer-Ausgabe ein benutzerdefiniertes schreibgeschütztes Feld hinzufügen, das von einer im Serializer definierten Methode stammt.

Der read_only_custom_model_field Verwendet eine Methode für Ihr Modell, um einige Daten zu lesen, nicht ausschließlich ein Modellfeld, sondern eine benutzerdefinierte Methode. Das heißt,.

class MyModel(models.Model):
    my_field = models.CharField(max_length=100)

    @property
    def custom_property(self):
        return "Perform calculations, combine with related models, etc. etc."
47
A. J. Parr

Nur ein Beispiel könnte Ihnen helfen.

  class ExtensibleModelSerializerOptions(serializers.SerializerOptions):
    """
    Meta class options for ModelSerializer
    """
    def __init__(self, meta):
        super(ExtensibleModelSerializerOptions, self).__init__(meta)
        self.model = getattr(meta, 'model', None)
        self.read_only_fields = getattr(meta, 'read_only_fields', ())
        self.non_native_fields = getattr(meta, 'non_native_fields', ())


class ExtensibleModelSerializer(serializers.ModelSerializer):

    _options_class = ExtensibleModelSerializerOptions

    def restore_object(self, attrs, instance=None):
        """
        Deserialize a dictionary of attributes into an object instance.
        You should override this method to control how deserialized objects
        are instantiated.
        """
        for field in self.opts.non_native_fields:
            attrs.pop(field)

        return super(ExtensibleModelSerializer, self).restore_object(attrs, instance)

Quelle: https://github.com/tomchristie/Django-rest-framework/issues/951

2
chandu
class Foo(models.Model):
    . . .
    @property
    def my_field(self):
        return stuff
    . . .

Quelle:

Django REST Framework: Hinzufügen eines zusätzlichen Felds zu ModelSerializer

1
chandu

Wie bereits erwähnt, gibt es zwei Möglichkeiten. (1) Hinzufügen einer Modelleigenschaft. (2) Hinzufügen eines Modellfeldes. Ich bin der Meinung, dass das Hinzufügen einer @ Eigenschaft zum Modell in diesem Beitrag gut erklärt wurde. Wenn Sie Ihre Modelle "schlank und gemein" halten möchten, verwenden Sie ein Methodenfeld. Die Antwort von Chandus lässt jedoch einige entscheidende Punkte aus:

class DeliveryItemSerializer(serializers.ModelSerializer):

    product_name = serializers.SerializerMethodField(read_only=True)

    def get_product_name(self, obj):
        return obj.product.name

    class Meta:
        model = DeliveryItem
        fields = (
            (...your field names),
            'product_name',)
  1. Nur read_only setzen
  2. Das Feld und die entsprechende Methode haben nicht denselben Namen. Der Methodenname lautet standardmäßig get_ Feldname. Wenn Sie einen anderen Namen verwenden, verwenden Sie das Argument method_name=method Name für SerializerMethodField()
0
Xen_mar