如何为序列化程序方法结果创建 json 属性
How to create a json attribute for a serializer method result
这里我有一个序列化器,在那个序列化器中是一个 get_is_liked
方法。
此方法将 return 一个布尔值,无论 post 是否被当前用户喜欢。
现在,我想像其他字段一样以 json 属性的格式获取此方法的结果。
假设有一个移动应用程序向登录用户发送请求以显示 post 之前是否喜欢过。
serializer.py
class BookSerializer(serializers.ModelSerializer):
user = serializers.SlugRelatedField(slug_field='username', read_only=True)
class Meta:
fields = (
'id',
'name',
'description',
'user',
'likes'
)
model = models.Book
def get_is_liked(self, obj):
requestUser = self.context['request'].user
return models.BookLike.objects.filter(
book=obj,
liker=requestUser
).exists()
views.py
class ListBookView(generics.ListCreateAPIView):
permission_classes = (IsAuthenticated, )
queryset = models.Book.objects.all()
serializer_class = serializers.BookSerializer
def perform_create(self, serializer):
serializer.save(user=self.request.user)
class DetailBookView(generics.RetrieveUpdateDestroyAPIView):
permission_classes = (IsOwnerOrReadOnly, )
queryset = models.Book.objects.all()
serializer_class = serializers.BookSerializer
已编辑:
models.py
class Book(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=125)
description = models.CharField(max_length=225)
likes = models.PositiveIntegerField(default=0)
def __str__(self):
return self.name
class BookLike(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE)
liker = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return 'Post: {0}, Liked by {1}'.format(self.book, self.liker)
现在,我不知道该怎么做?!
使用SerializerMethodField
创建一个只读字段并通过调用序列化器上的方法获取其值class。
在名为 get_<field_name>
的序列化程序上创建一个字段和一个方法。此方法有两个参数:self
和被序列化的给定对象(就像您的 get_is_liked()
方法)
serializers.py
class BookSerializer(serializers.ModelSerializer):
is_liked = serializers.SerializerMethodField()
likes = serializers.SerializerMethodField()
def get_is_liked(self, obj):
'''
Returns a boolean that represents whether the book has
already been liked by the user
'''
return models.BookLike.objects.filter(
book=obj,
liker=self.context['request'].user
).exists()
def get_likes(self, obj):
'''
Returns the numer of likes of the book
'''
return models.BookLike.objects.filter(book=obj).count()
实施点赞的端点
get_is_liked()
将始终 return False
直到 API 允许用户为一本书点赞。将需要创建一个新端点来执行此操作。
我建议您将视图合并到一个视图集中并添加一个额外的操作(请参阅 documentation)以执行类似的功能。类似于:
from rest_framework.decorators import action
class BookViewSet(generics.ModelViewSet):
permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
queryset = models.Book.objects.all()
serializer_class = serializers.BookSerializer
@action(methods=['post'], detail=True)
def like(self, request, pk=None):
book = self.get_object()
# Create a like for the book or get an existent one
like, created = BookLike.objects.get_or_create(
book=book,
liker=request.user
)
# User never gave a like for this book
if created:
return Response({
'detail': 'Your like was registered with success.'
})
# Book already liked by the user (dislike or error?)
return Response({
'detail': 'Only one like per book is allowed.'
}, status.HTTP_400_BAD_REQUEST)
urls.py
from rest_framework.routers import DefaultRouter
from django.urls import path, include
from . import views
router = DefaultRouter()
router.register(r'books', views.BookViewSet, base_name='book')
urlpatterns = [
path('', include(router.urls)),
]
使用此配置,点赞的终点是
POST /books/{bookId}/like/
这里我有一个序列化器,在那个序列化器中是一个 get_is_liked
方法。
此方法将 return 一个布尔值,无论 post 是否被当前用户喜欢。
现在,我想像其他字段一样以 json 属性的格式获取此方法的结果。 假设有一个移动应用程序向登录用户发送请求以显示 post 之前是否喜欢过。
serializer.py
class BookSerializer(serializers.ModelSerializer):
user = serializers.SlugRelatedField(slug_field='username', read_only=True)
class Meta:
fields = (
'id',
'name',
'description',
'user',
'likes'
)
model = models.Book
def get_is_liked(self, obj):
requestUser = self.context['request'].user
return models.BookLike.objects.filter(
book=obj,
liker=requestUser
).exists()
views.py
class ListBookView(generics.ListCreateAPIView):
permission_classes = (IsAuthenticated, )
queryset = models.Book.objects.all()
serializer_class = serializers.BookSerializer
def perform_create(self, serializer):
serializer.save(user=self.request.user)
class DetailBookView(generics.RetrieveUpdateDestroyAPIView):
permission_classes = (IsOwnerOrReadOnly, )
queryset = models.Book.objects.all()
serializer_class = serializers.BookSerializer
已编辑:
models.py
class Book(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=125)
description = models.CharField(max_length=225)
likes = models.PositiveIntegerField(default=0)
def __str__(self):
return self.name
class BookLike(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE)
liker = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return 'Post: {0}, Liked by {1}'.format(self.book, self.liker)
现在,我不知道该怎么做?!
使用SerializerMethodField
创建一个只读字段并通过调用序列化器上的方法获取其值class。
在名为 get_<field_name>
的序列化程序上创建一个字段和一个方法。此方法有两个参数:self
和被序列化的给定对象(就像您的 get_is_liked()
方法)
serializers.py
class BookSerializer(serializers.ModelSerializer):
is_liked = serializers.SerializerMethodField()
likes = serializers.SerializerMethodField()
def get_is_liked(self, obj):
'''
Returns a boolean that represents whether the book has
already been liked by the user
'''
return models.BookLike.objects.filter(
book=obj,
liker=self.context['request'].user
).exists()
def get_likes(self, obj):
'''
Returns the numer of likes of the book
'''
return models.BookLike.objects.filter(book=obj).count()
实施点赞的端点
get_is_liked()
将始终 return False
直到 API 允许用户为一本书点赞。将需要创建一个新端点来执行此操作。
我建议您将视图合并到一个视图集中并添加一个额外的操作(请参阅 documentation)以执行类似的功能。类似于:
from rest_framework.decorators import action
class BookViewSet(generics.ModelViewSet):
permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
queryset = models.Book.objects.all()
serializer_class = serializers.BookSerializer
@action(methods=['post'], detail=True)
def like(self, request, pk=None):
book = self.get_object()
# Create a like for the book or get an existent one
like, created = BookLike.objects.get_or_create(
book=book,
liker=request.user
)
# User never gave a like for this book
if created:
return Response({
'detail': 'Your like was registered with success.'
})
# Book already liked by the user (dislike or error?)
return Response({
'detail': 'Only one like per book is allowed.'
}, status.HTTP_400_BAD_REQUEST)
urls.py
from rest_framework.routers import DefaultRouter
from django.urls import path, include
from . import views
router = DefaultRouter()
router.register(r'books', views.BookViewSet, base_name='book')
urlpatterns = [
path('', include(router.urls)),
]
使用此配置,点赞的终点是
POST /books/{bookId}/like/