Django REST Framework:ModelSerializer 是否可以选择通过 GET 或 (POST, PUT, DELETE) 动态更改字段?
Django REST Framework: Does ModelSerializer have an option to change the fields dynamically by GET or (POST, PUT, DELETE)?
ModelSerializer 是否可以选择通过 GET 或(POST、PUT、DELETE)动态更改字段?
虽然 GET 需要复杂的字段,例如嵌套序列化程序,但 (POST、PUT、DELETE) 不需要这些。
我认为解决方案是为 GET 和(POST、PUT、DELETE)使用单独的序列化程序。
但在那种情况下,我将不得不创建很多无用的序列化程序。
有什么好的解决办法吗?
class PlaylistSerializer(serializers.ModelSerializer):
user = UserDetailSerializer(read_only=True)
tracks = serializers.SerializerMethodField()
is_owner = serializers.SerializerMethodField()
is_added = serializers.SerializerMethodField()
is_favorited = serializers.BooleanField()
class Meta:
model = Playlist
fields = (
"pk",
"user",
"title",
"views",
"is_public",
"is_wl",
"created_at",
"updated_at",
"tracks",
"is_owner",
"is_added",
"is_favorited",
)
def get_is_owner(self, obj):
return obj.user == self.context["request"].user
def get_tracks(self, obj):
queryset = obj.track_set
if queryset.exists():
tracks = TrackSerializer(queryset, context=self.context, many=True).data
return tracks
else:
return []
def get_is_added(self, obj):
try:
return obj.is_added
except AttributeError:
return False
class PlaylistUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Playlist
fields = ("title", "is_public")
首先您需要创建一个 class 并从此 class 继承您的序列化程序,如下所示:
from rest_framework import serializers
class DynamicFieldsModelSerializer(serializers.ModelSerializer):
"""To be used alongside DRF's serializers.ModelSerializer"""
@classmethod
def default_fieldset(cls):
return cls.Meta.fields
def __init__(self, *args, **kwargs):
self.requested_fields = self._extract_fieldset(**kwargs)
# Fields should be popped otherwise next line complains about
unexpected kwarg
kwargs.pop('fields', None)
super().__init__(*args, **kwargs)
self._limit_fields(self.requested_fields)
def _extract_fieldset(self, **kwargs):
requested_fields = kwargs.pop('fields', None)
if requested_fields is not None:
return requested_fields
context = kwargs.pop('context', None)
if context is None:
return None
return context.get('fields')
def _limit_fields(self, allowed_fields=None):
if allowed_fields is None:
to_exclude = set(self.fields.keys()) - set(self.default_fieldset())
else:
to_exclude = set(self.fields.keys()) - set(allowed_fields)
for field_name in to_exclude or []:
self.fields.pop(field_name)
@classmethod
def all_fields_minus(cls, *removed_fields):
return set(cls.Meta.fields) - set(removed_fields)
那么你的序列化程序将是这样的:
class PlaylistSerializer(DynamicFieldsModelSerializer):
class Meta:
model = Playlist
fields = ("pk", "user", "title", "views", "is_public",
"is_wl", "created_at", "updated_at", "tracks", "is_owner",
"is_added", "is_favorited",)
@classmethod
def update_serializer(cls):
return ("title", "is_public")
@classmethod
def view_serializer(cls):
return ("title", "is_public", "is_owner", "is_added")
然后你将调用你的序列化程序如下:
PlaylistSerializer(instance, fields=PlaylistSerializer.update_serializer()).data
ModelSerializer 是否可以选择通过 GET 或(POST、PUT、DELETE)动态更改字段?
虽然 GET 需要复杂的字段,例如嵌套序列化程序,但 (POST、PUT、DELETE) 不需要这些。
我认为解决方案是为 GET 和(POST、PUT、DELETE)使用单独的序列化程序。 但在那种情况下,我将不得不创建很多无用的序列化程序。 有什么好的解决办法吗?
class PlaylistSerializer(serializers.ModelSerializer):
user = UserDetailSerializer(read_only=True)
tracks = serializers.SerializerMethodField()
is_owner = serializers.SerializerMethodField()
is_added = serializers.SerializerMethodField()
is_favorited = serializers.BooleanField()
class Meta:
model = Playlist
fields = (
"pk",
"user",
"title",
"views",
"is_public",
"is_wl",
"created_at",
"updated_at",
"tracks",
"is_owner",
"is_added",
"is_favorited",
)
def get_is_owner(self, obj):
return obj.user == self.context["request"].user
def get_tracks(self, obj):
queryset = obj.track_set
if queryset.exists():
tracks = TrackSerializer(queryset, context=self.context, many=True).data
return tracks
else:
return []
def get_is_added(self, obj):
try:
return obj.is_added
except AttributeError:
return False
class PlaylistUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Playlist
fields = ("title", "is_public")
首先您需要创建一个 class 并从此 class 继承您的序列化程序,如下所示:
from rest_framework import serializers
class DynamicFieldsModelSerializer(serializers.ModelSerializer):
"""To be used alongside DRF's serializers.ModelSerializer"""
@classmethod
def default_fieldset(cls):
return cls.Meta.fields
def __init__(self, *args, **kwargs):
self.requested_fields = self._extract_fieldset(**kwargs)
# Fields should be popped otherwise next line complains about
unexpected kwarg
kwargs.pop('fields', None)
super().__init__(*args, **kwargs)
self._limit_fields(self.requested_fields)
def _extract_fieldset(self, **kwargs):
requested_fields = kwargs.pop('fields', None)
if requested_fields is not None:
return requested_fields
context = kwargs.pop('context', None)
if context is None:
return None
return context.get('fields')
def _limit_fields(self, allowed_fields=None):
if allowed_fields is None:
to_exclude = set(self.fields.keys()) - set(self.default_fieldset())
else:
to_exclude = set(self.fields.keys()) - set(allowed_fields)
for field_name in to_exclude or []:
self.fields.pop(field_name)
@classmethod
def all_fields_minus(cls, *removed_fields):
return set(cls.Meta.fields) - set(removed_fields)
那么你的序列化程序将是这样的:
class PlaylistSerializer(DynamicFieldsModelSerializer):
class Meta:
model = Playlist
fields = ("pk", "user", "title", "views", "is_public",
"is_wl", "created_at", "updated_at", "tracks", "is_owner",
"is_added", "is_favorited",)
@classmethod
def update_serializer(cls):
return ("title", "is_public")
@classmethod
def view_serializer(cls):
return ("title", "is_public", "is_owner", "is_added")
然后你将调用你的序列化程序如下:
PlaylistSerializer(instance, fields=PlaylistSerializer.update_serializer()).data