【问题标题】:Django serialize object with information from other modelDjango使用来自其他模型的信息序列化对象
【发布时间】:2019-11-21 04:13:03
【问题描述】:

当前代码

我有两个模型(Post 和 View),如下所示。 View 是指哪个用户看过哪个帖子。

帖子模型:

class Post(models.Model):

    creator = models.ForeignKey(User, on_delete = models.CASCADE)
    text = models.CharField(max_length = 255)
    timestamp = models.DateTimeField(default=now)

    def __str__(self):
        return str(self.pk)

查看模型:

class View(models.Model):

    viewer = models.ForeignKey(User, on_delete = models.CASCADE)
    post = models.ForeignKey(Post, on_delete = models.CASCADE)
    timestamp = models.DateTimeField(default=now)

    def __str__(self):
        return str(self.post.pk)

    class Meta:
        unique_together = ('post', 'viewer')

我的 views.py 目前看起来像这样:

@api_view(['GET'])
@login_required
def get_posts(request):

     posts = list(Post.objects.all())
     data = serialize('json', posts, use_natural_foreign_keys=True)
     return HttpResponse(data, content_type="application/json")

问题

现在我希望能够序列化许多 Post 对象,并为每个对象添加一个属性,说明发出请求的用户 (request.user) 是否查看了 Post。

我希望收到的结果示例:

[
{
    "model": "posts.post",
    "pk": 1,
    "fields": {
        "creator": ...,
        "content": "This is a sample post",
        "timestamp": "2019-07-07T19:56:07.220Z",
        "viewed_by_user": true <--- I want this attribute
    }
},
{
    "model": "posts.post",
    "pk": 2,
    "fields": {
        "creator": ...,
        "content": "This is another sample post",
        "timestamp": "2019-07-10T13:04:19.220Z",
        "viewed_by_user": false <--- I want this attribute
    }
}
]

我可以使用 django 序列化程序来实现这一点吗?我应该以不同的方式构建模型吗?

我正在使用 django-rest-framework 来处理请求。您可以问我是否需要任何其他信息才能回答我的问题。任何帮助将不胜感激。

【问题讨论】:

  • 如果你使用 DRF,你应该使用 DRF 序列化器类,而不是根本无法定制的基本 Django 类。
  • 是的,但我不熟悉如何使用它们来解决这个确切的问题。

标签: python json django serialization django-rest-framework


【解决方案1】:

您可以使用来自 DRF 的标准 ModelSerializer

序列化器.py

from rest_framework import serializers

from .models import Post


class PostSerializer(serializers.ModelSerializer):
    viewed_by_user = serializers.SerializerMethodField()

    class Meta:
        model = Post
        fields = ('pk', 'creator', 'text', 'timestamp', 'viewed_by_user')

    def get_viewed_by_user(self, instance):
        user = self.context['request']. user
        return instance.view_set.filter(viewer=user).exists()

然后

views.py

from rest_framework.response import Response
...

from .serializers import PostSerializer


@api_view(['GET'])
@login_required
def get_posts(request):
     posts = Post.objects.all()
     serializer = PostSerializer(posts, many=True, context={'request': request})
     return Response(serializer.data)

在您的视图中,您可以通过将当前的request 对象作为上下文提供给序列化程序来使用新创建的PostSerializer

之后,您可以从SerializerMethodField 中受益,以显示viewed_by_user 属性。

如果您有任何其他问题,请务必在下方发表评论。 :)

【讨论】:

  • 感谢您的回答。这就是我需要的。您忘记了 serializers.py 中 user = self.context['request'] 中的 .user。我做到了user = self.context['request'].user 并且成功了!
  • @Thanasis1101 哎呀。我已经编辑了我的答案,谢谢。 :)
【解决方案2】:

您可以通过使用DRF 来实现这一点,并且您不需要单独的模型来计算查看特定帖子的用户数

models.py

class Post(models.Model):

    creator = models.ForeignKey(User, on_delete = models.CASCADE)
    text = models.CharField(max_length = 255)
    timestamp = models.DateTimeField(default=now)
    viewed_by = models.ManyToManyField(User, null=True, blank=True, related_name='viewer')

    def __str__(self):
        return str(self.pk)

serializers.py

使用serializerMethord 来检查用户是否查看了特定帖子

from rest_framework import serializers
from .models import Post


    class PostSerializers(serializers.ModelSerializer):

        viewed = serializers.SerializerMethodField()

        class Meta:
            model = Post
            fields = [
                'viewed',
                'text',
                'timestamp'

            ]

        def get_viewed(self, obj):
            print(self.context['request'].user, obj.viewed_by)
            if self.context['request'].user in obj.viewed_by.all():
                return True
            return False

然后在views.py

from rest_framework.generics import ListAPIView

from .models import Post
from .serializers import PostSerializers

    class PostListView(ListAPIView):
        queryset = Post.objects.all()
        serializer_class = PostSerializers

您可以通过

来计算每个视图
class PostDetailView(RetrieveAPIView):
    queryset = Post.objects.all()
    serializer_class = PostSerializers

    def get(self, request, *args, **kwargs):
        data = self.get_object()
        data.viewed_by.add(request.user)
        data.save()

        return self.retrieve(request, *args, **kwargs)

【讨论】:

  • 感谢 Post 模型中 viewed_by 的回答和建议。我可以使用它,但它会影响我使用的其他一些功能,所以我更喜欢保留模型,因为我现在拥有它们。但我会记住你的建议,以防我在其他地方需要它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-14
  • 1970-01-01
  • 1970-01-01
  • 2015-04-23
  • 1970-01-01
  • 2010-11-03
  • 2013-08-19
相关资源
最近更新 更多