【问题标题】:How to create a json attribute for a serializer method result如何为序列化程序方法结果创建 json 属性
【发布时间】:2019-05-28 14:42:35
【问题描述】:

这里我有一个序列化程序,其中的序列化程序是一个get_is_liked 方法。 此方法将返回一个布尔值,无论帖子是否被当前用户喜欢。

现在,我想像其他字段一样以 json 属性的格式获取此方法的结果。 假设有一个移动应用程序向登录用户发送请求,以显示该帖子之前是否喜欢过。

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)

现在,我不知道该怎么做?!

【问题讨论】:

    标签: python django-models django-rest-framework django-serializer


    【解决方案1】:

    使用SerializerMethodField 创建一个只读字段并通过调用序列化程序类上的方法获取其值。

    在名为get_<field_name> 的序列化程序上创建一个字段和一个方法。此方法有两个参数:self 和被序列化的给定对象(就像您的 get_is_liked() 方法一样)

    序列化器.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() 将始终返回 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)),
    ]
    

    使用此配置,like 的端点是

    POST /books/{bookId}/like/
    

    【讨论】:

    • 现在,它显示了 is_liked 字段,但它总是错误的。我的模型字段代码是:`class Book(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) name = models.CharField(max_length=125) likes = models.PositiveIntegerField(default=0) class BookLike (models.Model): book = models.ForeignKey(BookSuggest, on_delete=models.CASCADE) liker = models.ForeignKey(User, on_delete=models.CASCADE)
    • is_liked 字段始终为False,因为您的查询集没有在数据库上为登录用户找到任何BookLike 实例。您在哪里放置代码以在书中执行类似操作,即为登录用户创建一个 BookLike 实例?请将您的模型(BookBookLike)放在问题描述中以便于查看
    • 我确实将其添加到问题中。
    • 我使用的是User,并且还有一个外键,在BookLike类中命名为liker。
    • 但是,有一些端点可以为用户创建一个BookLike?类似BookLike.objects.create(liker=request.user, book=book)
    猜你喜欢
    • 2017-04-26
    • 1970-01-01
    • 2011-06-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多