Return only last entry of related model in seriali

2019-05-11 12:19发布

I have two Django models, Discussion and Post set up as follows:

Discussion model:

class Discussion(models.Model):
    Discussion_ID = models.AutoField(primary_key=True)
    Topic = models.CharField(max_length=50)
    Group = models.ForeignKey(Group, related_name="Group_Discussions")

    class Meta:
        db_table = "Discussions"        

Post model:

class Post(models.Model):
    Post_ID = models.AutoField(primary_key=True)
    Date_Posted = models.DateTimeField(auto_now_add=True)
    Discussion = models.ForeignKey(Discussion, db_column="Discussion_ID", related_name="Posts")
    User = models.ForeignKey(User, related_name="User_Posts")
    Message = models.TextField()

    class Meta:
        db_table = "Posts"

I want to serialize a list of all discussions, and in the serializer, include ONLY the latest post for each discussion. So far, my serializer looks like this:

class DiscussionSerializer(serializers.ModelSerializer):
    last_post = serializers.SerializerMethodField()
    post_count = serializers.SerializerMethodField()

    class Meta:
        model = Discussion
        fields = ('Discussion_ID', 'Topic', 'last_post', 'post_count')

    def get_last_post(self, obj):
        return Post.objects.raw("SELECT * FROM Posts WHERE Discussion_ID = %s ORDER BY Post_ID DESC LIMIT 1" % obj.Discussion_ID)

    def get_post_count(self, obj):
        return obj.Posts.count()

Unfortunately, this return the following error and I'm not quite sure what else to try:

<RawQuerySet: SELECT * FROM Posts WHERE Discussion_ID = 1 ORDER BY Post_ID DESC LIMIT 1> is not JSON serializable

Basically, I want to serialize the Discussion model along with the lastest post in the discussion into JSON that looks something like this:

{ 
    "Discussion_ID": 1, 
    "Topic": "Some topic",
    "last_post": { 
        "Post_ID": 1,
        "Date_Posted": "...",
        "Discussion": 1,
        "User": 1,
        "Message": "This is a message"
    },
    "post_count": 10
}

2条回答
够拽才男人
2楼-- · 2019-05-11 12:46

To improve your solution, you might want to move this code to a viewset method and handle some other things like permissions, applying filters for Posts (if you have any) and the "not found" error. For example:

class PostViewSet(viewsets.GenericViewSet, mixins.RetrieveModelMixin):

    #...

    def retrieve_last():

        queryset = self.filter_queryset(self.get_queryset())

        try:
            obj =  queryset.latest('Date_Posted')
        except queryset.model.DoesNotExist:
            raise Http404('No %s matches the given query.' \
                          % queryset.model._meta.object_name)

        self.check_object_permissions(self.request, obj)

        serializer = self.get_serializer(obj)

        return Response(serializer.data)

By the way, this is inspired by DRF's ModelViewSet.

查看更多
干净又极端
3楼-- · 2019-05-11 12:59

I managed to get this working with the following:

def get_last_post(self, obj):
    try:
        post = obj.Posts.latest('Date_Posted')
        serializer = PostSerializer(post)
        return serializer.data
    except Exception, ex:
        return None

It feels a bit hacky though so I am still open to other solutions.

查看更多
登录 后发表回答