Add a boolean field if a row exists in another table?

巧了我就是萌 提交于 2019-12-22 17:55:16

问题


I have two tables called Post and Reply. The users can create just one Response for each Post. The models look like this:

class Post(models.Model):
    name = models.CharField(max_length = 100)

class Reply(models.Model):
    post = models.ForeignKey(Post, related_name = 'replies')

Now, I have a view that returns the posts, like this:

class PostList(generics.ListAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    queryset = Post.objects.all()
    serializer_class = PostSerializer

And a serializer for the posts:

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        fields = ('id', 'name')

The results of this view look like this:

[
    {
        "id": "1",
        "name": "The first post"
    },
    {
        "id": "2",
        "name": "The second post"
    }
]

Now, to the actual problem in question: I'd like to have a boolean field in the results that'd be true if the user has replied to the post, and false if they hasn't. Basically, the result for a situation where the current user has replied to the first post but not the second post would look like this:

[
    {
        "id": "1",
        "name": "The first post",
        "replied": "true"
    },
    {
        "id": "2",
        "name": "The second post",
        "replied": "false"
    }
]

How do I achieve this? I have a hunch that this should be implemented in the serializer somehow, but I don't know how I'd do that.

Thanks in advance for all your help!


回答1:


Piggybacking off of dydek's answer here.

You overwrite your get_queryset in the Api View

class PostList(generics.ListAPIView):
    ...
    def get_queryset(self):
        Post.objects.all().extra(select={
        'current_user_replies_count': 'SELECT COUNT(*) FROM <reply table> WHERE' +
        'post_id=posts_post.id AND owner_id = %s'
                                  },select_params=(request.user.id,))

This will add 'current_user_replies_count' as a property to the Post objects in your queryset.




回答2:


The next problem here is to many sql queries when you'll be fetching eg. 100 objects (you will have BASE_QUERIES_COUNT + len(objects) ). Of corse we don't want to have linear sql queries count, and this situation should never happen, especially in production version. The perfect solution here would be if we would be able to have all data fetched in one sql query. This is possible with override get_queryset method ( here https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/generics.py#L47 ). And then queryset could look like below, param current_user_replies_count is available as normal model instance variable.

# all only for example
Post.objects.all().extra(select={
        'current_user_replies_count': 'SELECT COUNT(*) FROM <reply table> WHERE '+
                                      'post_id=posts_post.id AND owner_id = %s'
    },
    select_params=(request.user.id,)
)

I haven't tested it, so use it more as example instead of ready solution, and you should cast current_user_replies_count to bool.




回答3:


You can add custom fields to your PostSerializer

class PostSerializer(serializers.ModelSerializer):
    replied = serializers.SerializerMethodField('has_replies')

    def has_replies(post):
        return post.replies.filter(owner=self.context["request"].user).exists()

    class Meta:
        fields = ('id', 'name', 'replied')


来源:https://stackoverflow.com/questions/30640723/add-a-boolean-field-if-a-row-exists-in-another-table

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!