簡體   English   中英

在 DRF 3 的 ModelSerializer 上添加一個非模型字段

[英]Add a non-model field on a ModelSerializer in DRF 3

如何在 DRF 3 中的 ModelSerializer 上添加非模型字段? 即添加一個在我的實際 model 上不存在的字段?

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

但是 DRF 3 給我錯誤:

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

我搜索了 stack DRF - ModelSerializer with a non-model write_only field並找到了一些解決方案,但這些解決方案指的是我正在使用 DRF 3 的 DRF 2。這個版本有解決方案嗎?

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)

serializers.CharField(write_only=True)serializers.ListField(...)是一個很好的解決方案,可以為.create.update方法提供額外的數據,可以是單個字符串或字符串列表(可以混合ListField與其他序列化程序字段類型)。 使用此方法,您還可以定義def validate_write_only_char_field以實現一些快速簡單的驗證。

serializers.SerializerMethodField()允許您從序列化程序中定義的方法向序列化程序輸出添加一些自定義只讀字段。

read_only_custom_model_field將使用模型上的方法來讀取一些數據,而不是嚴格的模型字段,而是自定義方法。

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

或者瀏覽此鏈接

只是一個例子可能會幫助你。

  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)

資料來源: https//github.com/tomchristie/django-rest-framework/issues/951

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

資源:

Django REST Framework:向ModelSerializer添加其他字段

如上所述,有兩種方法。 (1)添加模型屬性。 (2)添加模型字段。 我覺得在這篇文章中很好地解釋了在模型中添加@property。 如果您想讓模型“精益求精”,請使用“方法”字段。 Chandus的回答省略了一些關鍵點,但是:

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. 設置read_only
  2. 該字段和相應的方法不具有相同的名稱。 該方法的名稱默認為get_ FIELD_NAME。 如果使用其他名稱,請在SerializerMethodField()上使用method_name=method name參數

在之前的所有回答中,我看到每個人都建議刪除那些不屬於 Django model..

所以這不是遵循單一責任主體

def create(self, validated_data):
    pass

根據drf drf doc這個function只負責創建。

但如果您只想添加一些額外的字段作為響應,我們需要覆蓋

def to_representation(self,instance):
    pass

像這樣在序列化程序中提供序列化程序字段,

name = serializers.BooleanField(allow_null=True, required=False, default=False)

然后像這樣在序列化程序中使用 create function

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

現在你可以從前端輸入數據,它不會保存在 model 中。
要訪問該字段的數據,您將在 create function 視圖中獲取它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM