问题
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