Django Rest Framework只读模型序列化器

Moh*_*sen 15 python django-rest-framework

我想要一个完全只读ModelSerializer,即只是列表/检索方法

最好的方法是什么?

mga*_*lgs 13

您真的想在视图(或Viewset)级别执行此操作,您可以使用ReadOnlyModelViewSet执行此操作.

(你在评论中提到了这一点,但我将其作为更好的可见性的答案).


D W*_*D W 11

如果您使用的是 a ModelSerializer,则可以通过以下方式实现:

from rest_framework import serializers


class MyModelSerializer(serializers.ModelSerializer):
    ...

    class Meta:
        model = MyModel
        fields = ("field_1", "field_2", etc)
        read_only_fields = [f.name for f in MyModel._meta.get_fields()]
Run Code Online (Sandbox Code Playgroud)

该解决方案使用了_metadjango 模型的私有接口,但它相当稳定,并且被开发人员广泛使用。

在这里,我们只是生成相关模型中所有字段的列表,并将其应用于read_only_fields来自的选项django-rest-framework

我更喜欢在序列化程序级别而不是视图级别执行此操作,因为它不会将您束缚于使用 mgalgs 建议的Viewset

如果您想更进一步,您甚至可以将功能包装到一个 mixin 中,以添加到Meta您的类的选项中。例如:

from rest_framework import serializers
from rest_framework.fields import Field


class ReadOnlyMixin(Field):

    def __new__(cls, *args, **kwargs):
        setattr(
            cls.Meta,
            "read_only_fields",
            [f.name for f in cls.Meta.model._meta.get_fields()],
        )
        return super(ReadOnlyMixin, cls).__new__(cls, *args, **kwargs)


class MyModelSerializer(ReadOnlyMixin, serializers.ModelSerializer):
    ...

    class Meta:
        model = MyModel
        fields = ("field_1", "field_2", etc)
Run Code Online (Sandbox Code Playgroud)


Luk*_*ent 11

如果您确实需要只读的序列化程序,那么覆盖init方法是最简洁和稳定的选项:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    setattr(self.Meta, 'read_only_fields', [*self.fields])
Run Code Online (Sandbox Code Playgroud)

与上述相比:

  • @mgalgs 的解决方案是最好的,如果与使用的序列化程序无关的视图应该是只读的。
  • 如果您只有几个非动态字段,@thisisms 解决方案是最好的
  • @DW 的方法仅在没有使用“源”关键字的可写序列化程序字段时才有效。

编辑更好的解决方案: 您可以更新 def get_fields 方法而不是 init 方法并创建一个抽象序列化程序:

class ReadOnlyModelSerializer(serializers.ModelSerializer):
    def get_fields(self, *args, **kwargs):
        fields = super().get_fields(*args, **kwargs)
        for field in fields:
            fields[field].read_only = True
        return fields
Run Code Online (Sandbox Code Playgroud)

要使用它,只需从抽象序列化器继承:

def MySerializer(ReadOnlyModelSerializer):
   class Meta:
       model = MyModel
       fields = '__all__'
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的解决方案,它不使用任何私有字段,并且是可扩展的 - 如果您有很多只读序列化器,则可以在基类中使用它。 (2认同)

thi*_*sms 7

你唯一要做的就是创建一个像这样的序列化器.serializers.py

class YourdataSerializer(serializers.ModelSerializer):
    class Meta:
        model = Yourdata
        # some data
        fields = ('id', 'city', 'pincode', 'created')
        read_only_fields = ('id', 'city', 'pincode', 'created')
Run Code Online (Sandbox Code Playgroud)

观看这样的事情

class YourdataList(APIView):
    def get(self, request, format=None):
        yourdata = YourdataList.objects.all()
        serializer = YourdataSerializer(yourdata, many=True)
        return Response(serializer.data)
Run Code Online (Sandbox Code Playgroud)

详细视图

class YourdataDetail(APIView):
   def get_object(self, pk):
        try:
            return Yourdata.objects.get(pk=pk)
        except Yourdata.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = YourdataSerializer(snippet)
        return Response(serializer.data)
Run Code Online (Sandbox Code Playgroud)

这样做.

  • 使这更加简化的一种方法是在`Meta`中使用`read_only_fields = fields`. (4认同)