You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django REST API:返回关联对象而非ID并自动创建Options

解决方案

1. 修改序列化器,返回关联对象完整信息

修改serializers.py,通过嵌套序列化器替换默认的ID返回逻辑,同时重写创建/更新方法支持自动创建关联的Options:

from rest_framework import serializers
from rest_framework.validators import UniqueValidator
from devices import models

class OptionsSerializer(serializers.ModelSerializer):
    identifier = serializers.CharField(
        max_length=255,
        validators=[UniqueValidator(queryset=models.Options.objects.all())]
    )
    class Meta:
        model = models.Options
        fields = '__all__'

class GroupsSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Groups
        fields = '__all__'

class DevicesSerializer(serializers.ModelSerializer):
    # 嵌套序列化器,返回Group完整信息
    group = GroupsSerializer()
    # 嵌套序列化器,返回Options完整列表
    options = OptionsSerializer(many=True)

    class Meta:
        model = models.Devices
        fields = '__all__'

    def create(self, validated_data):
        # 提取嵌套的关联数据
        options_data = validated_data.pop('options')
        group_data = validated_data.pop('group')
        
        # 处理Group:存在则获取,不存在则创建
        group, _ = models.Groups.objects.get_or_create(**group_data)
        
        # 创建Device实例
        device = models.Devices.objects.create(group=group, **validated_data)
        
        # 批量处理Options:避免重复创建,已存在则直接关联
        existing_identifiers = [opt['identifier'] for opt in options_data]
        existing_options = models.Options.objects.filter(identifier__in=existing_identifiers)
        existing_opt_map = {opt.identifier: opt for opt in existing_options}
        
        new_options = []
        for opt_data in options_data:
            if opt_data['identifier'] not in existing_opt_map:
                new_options.append(models.Options(**opt_data))
        
        # 批量创建新Options
        if new_options:
            models.Options.objects.bulk_create(new_options)
        
        # 关联所有Options到Device
        all_options = models.Options.objects.filter(identifier__in=existing_identifiers)
        device.options.add(*all_options)
        
        return device

    def update(self, instance, validated_data):
        # 更新Device基础字段
        instance.name = validated_data.get('name', instance.name)
        instance.identifier = validated_data.get('identifier', instance.identifier)
        instance.save()
        
        # 更新Group
        group_data = validated_data.pop('group', None)
        if group_data:
            group, _ = models.Groups.objects.get_or_create(**group_data)
            instance.group = group
            instance.save()
        
        # 更新Options
        options_data = validated_data.pop('options', None)
        if options_data:
            instance.options.clear()
            existing_identifiers = [opt['identifier'] for opt in options_data]
            existing_options = models.Options.objects.filter(identifier__in=existing_identifiers)
            existing_opt_map = {opt.identifier: opt for opt in existing_options}
            
            new_options = []
            for opt_data in options_data:
                if opt_data['identifier'] not in existing_opt_map:
                    new_options.append(models.Options(**opt_data))
            
            if new_options:
                models.Options.objects.bulk_create(new_options)
            
            all_options = models.Options.objects.filter(identifier__in=existing_identifiers)
            instance.options.add(*all_options)
        
        return instance

2. 请求示例

创建Device时,需传入嵌套结构的JSON:

{
    "name": "New Smart Switch",
    "identifier": "switch_001",
    "group": {
        "name": "Living Room Devices"
    },
    "options": [
        {
            "name": "Turn On",
            "identifier": "switch_on"
        },
        {
            "name": "Turn Off",
            "identifier": "switch_off"
        }
    ]
}

3. 关键说明

  • 对于Group:使用get_or_create确保不会重复创建同名Group,若需严格按ID关联,可修改为get(id_group=group_data['id_group'])
  • 对于Options:通过批量查询和创建减少数据库交互,UniqueValidator保证identifier字段唯一性
  • 修改后,Devices列表/详情接口会直接返回Group和Options的完整对象信息,无需额外查询

内容的提问来源于stack exchange,提问作者Ricardo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 09:35:27