Django REST Framework优化JSON响应:消除外键字段重复显示
Got it, let's restructure your serializers to group messages by conversation_id and owner as you requested. Here's a step-by-step implementation:
1. Create a Sub-serializer for Individual Messages
First, make a lightweight serializer to handle the unique fields per message (sender and body):
class MessageDetailSerializer(serializers.ModelSerializer): sender = serializers.ReadOnlyField(source='sender.id') class Meta: model = Message # Replace with your actual Message model name fields = ['sender', 'body']
2. Build a Custom List Serializer for Grouping
Next, we'll override DRF's ListSerializer to group messages by their shared conversation_id and owner:
class GroupedMessageListSerializer(serializers.ListSerializer): def to_representation(self, data): # Group messages by (conversation_id, owner) pair message_groups = {} for message in data: # Use the unique pair as a key for grouping group_key = (message.conversation_id, message.owner) if group_key not in message_groups: # Initialize a new group with shared fields message_groups[group_key] = { 'conversation_id': message.conversation_id, 'owner': message.owner, 'messages': [] } # Add the message details using our sub-serializer detail_serializer = MessageDetailSerializer(message, context=self.context) message_groups[group_key]['messages'].append(detail_serializer.data) # Convert the grouped dict back to a list for the response return list(message_groups.values())
Note for SerializerMethodField conversation_id:
If your conversation_id is defined via a SerializerMethodField (like your original code hints), replace message.conversation_id with a call to that method. For example:
# Inside GroupedMessageListSerializer's to_representation # First, create an instance of your original serializer to access the method parent_serializer = MessageSerializer(message, context=self.context) conv_id = parent_serializer.get_conversation_id(message) group_key = (conv_id, message.owner) # Then use conv_id when initializing the group
3. Update Your Original Message Serializer
Modify your main MessageSerializer to use the custom list serializer, and adjust fields to only include per-message data:
class MessageSerializer(serializers.ModelSerializer): sender = serializers.ReadOnlyField(source='sender.id') # Remove conversation_id from here since it's handled in the group class Meta: model = Message fields = ['sender', 'body'] # Tell DRF to use our grouped list serializer for bulk responses list_serializer_class = GroupedMessageListSerializer # Keep your existing get_conversation_id method if needed # def get_conversation_id(self, obj): # return obj.conversation.id # Example implementation
How It Works
When your DRF view returns a list of messages, the GroupedMessageListSerializer will:
- Iterate through all message instances
- Group them by their shared
conversation_idandowner - Nest individual message details under a
messagesarray for each group - Return the grouped structure as the
resultsarray in your response
The pagination fields (count, next, previous) will remain unchanged since DRF's pagination system uses the original queryset count.
Example Output
You'll get exactly the structure you wanted:
{ "count": 2, "next": null, "previous": null, "results": [ { "conversation_id": 1, "owner": true, "messages": [ { "sender": 2, "body": "Hello There" }, { "sender": 2, "body": "Second message" } ] } ] }
内容的提问来源于stack exchange,提问作者Roma

