web-dev-qa-db-fra.com

Ajouter un champ non modèle sur un ModelSerializer dans DRF 3

Comment ajouter un champ non-modèle sur un ModelSerializer dans DRF 3? c'est-à-dire ajouter un champ qui n'existe pas sur mon modèle actuel?

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

Mais DRF 3 me donne l'erreur:

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

J'ai cherché pile DRF - ModelSerializer avec un champ write_only non-modèle et trouvé quelques solutions mais celles-ci se réfèrent à DRF 2 où j'utilise DRF 3. Existe-t-il une solution pour cela sur cette version?

25
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

ou passez par là lien

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)

La fonction serializers.CharField(write_only=True) et serializers.ListField(...) est une bonne solution pour fournir des données supplémentaires à vos méthodes .create Et .update, Sous la forme d'une chaîne unique ou d'une liste de chaînes (vous pouvez mélanger ListField avec d'autres types de champs de sérialiseur). Avec cette méthode, vous pouvez également définir def validate_write_only_char_field Pour implémenter une validation simple et rapide.

serializers.SerializerMethodField() vous permet d'ajouter un champ personnalisé en lecture seule à la sortie de votre sérialiseur à partir d'une méthode définie sur le sérialiseur.

Le read_only_custom_model_field Utiliserait une méthode sur votre modèle pour lire certaines données, pas strictement un champ de modèle, mais une méthode personnalisée. C'est à dire.

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

Un simple exemple pourrait vous aider.

  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)

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

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

La source:

Django REST Framework: ajout d'un champ supplémentaire à ModelSerializer

1
chandu

Comme mentionné, il y a deux façons. (1) ajout d'une propriété de modèle. (2) ajouter un champ de modèle. Je pense que l'ajout d'une @ propriété au modèle a été bien expliqué dans ce post. Si vous voulez garder vos modèles "lean and mean", utilisez un champ Méthode. La réponse de Chandus omet cependant certains points cruciaux:

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. Définissez read_only
  2. Le champ et la méthode correspondante n'ont pas le même nom. Le nom de la méthode par défaut est get_ Nom_champ. Si vous utilisez un autre nom, utilisez l'argument de nom method_name=method Sur SerializerMethodField()
0
Xen_mar