django rest framework隐藏列表显示中的特定字段?

Dee*_*ena 9 python django django-rest-framework

我想在列表显示中隐藏模型的特定字段,persons/并显示详细信息显示上的所有字段persons/jane

我对其余框架相对较新,文档感觉很难掌握.

这就是我想要实现的目标.

我有一个简单的Person模型,

# model
class Person(models.Model):
    first_name = models.CharField(max_length=30, blank=True)
    last_name = models.CharField(max_length=30, blank=True)
    nickname = models.CharField(max_length=20)
    slug = models.SlugField()
    address = models.TextField(max_length=300, blank=True)
Run Code Online (Sandbox Code Playgroud)

和序列化器类

# serializers

class PersonListSerializer(serializers.ModelSerializer):
    class Meta:
        model = Person
        fields = ('nickname', 'slug')


class PersonSerializer(serializers.ModelSerializer):
    class Meta:
        model = Person
        fields = ('first_name', 'last_name', 'nickname', 'slug', 'address')
Run Code Online (Sandbox Code Playgroud)

和视图集.

# view sets (api.py)

class PersonListViewSet(viewsets.ModelViewSet):
    queryset = Person.objects.all()
    serializer_class = PersonListSerializer


class PersonViewSet(viewsets.ModelViewSet):
    queryset = Person.objects.all()
    serializer_class = PersonSerializer
Run Code Online (Sandbox Code Playgroud)

在网址上persons我想要显示人员列表,只需要字段nickname,slug并在网址上persons/[slug]我想显示模型的所有字段.

我的路由器配置,

router = routers.DefaultRouter()
router.register(r'persons', api.PersonListViewSet)
router.register(r'persons/{slug}', api.PersonViewSet)
Run Code Online (Sandbox Code Playgroud)

我猜第二种配置是错误的,我怎样才能实现我想做的事情?

更新:

输出到persons/slug是{"detail":"Not found."},但它适用于person/pk

谢谢

Liz*_*Liz 17

对于其他遇到此问题的人,我发现在视图集上覆盖 get_serializer_class 并为每个操作定义一个序列化器是 DRY-est 选项(保留单个视图集但允许动态序列化器选择):

class MyViewset(viewsets.ModelViewSet):
    serializer_class = serializers.ListSerializer
    permission_classes = [permissions.IsAdminUser]
    renderer_classes = (renderers.AdminRenderer,)
    queryset = models.MyModel.objects.all().order_by('-updated')

    def __init__(self, *args, **kwargs):
        super(MyViewset, self).__init__(*args, **kwargs)
        self.serializer_action_classes = {
            'list':serializers.AdminListSerializer,
            'create':serializers.AdminCreateSerializer,
            'retrieve':serializers.AdminRetrieveSerializer,
            'update':serializers.AdminUpdateSerializer,
            'partial_update':serializers.AdminUpdateSerializer,
            'destroy':serializers.AdminRetrieveSerializer,
        }

    def get_serializer_class(self, *args, **kwargs):
        """Instantiate the list of serializers per action from class attribute (must be defined)."""
        kwargs['partial'] = True
        try:
            return self.serializer_action_classes[self.action]
        except (KeyError, AttributeError):
            return super(MyViewset, self).get_serializer_class()
Run Code Online (Sandbox Code Playgroud)

希望这对其他人有帮助。


小智 10

您可以重写序列化器类的“get_fields”方法并添加类似的内容:

def get_fields(self, *args, **kwargs):
    fields = super().get_fields(*args, **kwargs)
    request = self.context.get('request')
    if request is not None and not request.parser_context.get('kwargs'):
        fields.pop('your_field', None)
    return fields
Run Code Online (Sandbox Code Playgroud)

在这种情况下,当您获得详细视图时,会有'kwargs': {'pk': 404},当您获得列表视图时,会有'kwargs': {}


Gre*_*ica 7

我编写了一个名为drf-action-serializer( pypi )的扩展,它添加了一个名为的序列化程序ModelActionSerializer,允许您在每个操作的基础上定义 fields/exclude/extra_kwargs(同时仍然有正常的 fields/exclude/extra_kwargs 可以依靠)。

实现很好,因为您不必覆盖 ViewSetget_serializer方法,因为您只使用一个序列化程序。相关的变化是在序列化程序的get_fields和get_extra_kwargs方法中,它检查视图操作,如果该操作存在于Meta.action_fields字典中,则它使用该配置而不是Meta.fields属性。

在您的示例中,您将执行以下操作:

from action_serializer import ModelActionSerializer

class PersonSerializer(ModelActionSerializer):
    class Meta:
        model = Person
        fields = ('first_name', 'last_name', 'nickname', 'slug', 'address')
        action_fields = {
            'list': {'fields': ('nickname', 'slug')}
        }
Run Code Online (Sandbox Code Playgroud)

您的 ViewSet 将类似于:

class PersonViewSet(viewsets.ModelViewSet):
    queryset = Person.objects.all()
    serializer_class = PersonSerializer
Run Code Online (Sandbox Code Playgroud)

你的路由器看起来也很正常:

router = routers.DefaultRouter()
router.register(r'persons', api.PersonViewSet)
Run Code Online (Sandbox Code Playgroud)

执行

如果你好奇我是如何实现的:

  1. 我添加了一个辅助方法,调用get_action_config它获取当前视图操作并在action_fields字典中返回该条目:
def get_action_config(self):
    """
    Return the configuration in the `Meta.action_fields` dictionary for this
    view's action.
    """
    view = getattr(self, 'context', {}).get('view', None)
    action = getattr(view, 'action', None)
    action_fields = getattr(self.Meta, 'action_fields', {})
Run Code Online (Sandbox Code Playgroud)
  1. 我改变get_field_names了ModelSerializer:

从:

fields = getattr(self.Meta, 'fields', None)
exclude = getattr(self.Meta, 'exclude', None)
Run Code Online (Sandbox Code Playgroud)

到:

action_config = self.get_action_config()
if action_config:
    fields = action_config.get('fields', None)
    exclude = action_config.get('exclude', None)
else:
    fields = getattr(self.Meta, 'fields', None)
    exclude = getattr(self.Meta, 'exclude', None)
Run Code Online (Sandbox Code Playgroud)
  1. 最后,我改变了get_extra_kwargs方法:

从:

extra_kwargs = copy.deepcopy(getattr(self.Meta, 'extra_kwargs', {}))
Run Code Online (Sandbox Code Playgroud)

到:

action_config = self.get_action_config()
if action_config:
    extra_kwargs = copy.deepcopy(action_config.get('extra_kwargs', {}))
else:
    extra_kwargs = copy.deepcopy(getattr(self.Meta, 'extra_kwargs', {}))
Run Code Online (Sandbox Code Playgroud)


Tan*_*ash 2

如果您想更改“列表与详细信息”视图中显示的字段,您唯一能做的就是更改所使用的序列化程序。据我所知,没有任何字段可以让您指定使用序列化器的哪些字段。