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

基于Django REST Framework嵌套序列化器的单次调用CRUD接口实现

基于Django REST Framework嵌套序列化器实现单次API调用的CRUD完整实现

现有代码

models.py

class User(models.Model):
    ROLE_CHOICES = (
        ("admin","ADMIN"),
        ("staff","STAFF")
    )

    username = models.CharField(max_length=256)
    password = models.CharField(max_length=256)
    firstname = models.CharField(max_length=256)
    lastname = models.CharField(max_length=256)
    email = models.CharField(max_length=256)
    role = models.CharField(max_length=256,choices=ROLE_CHOICES)

class Profile(models.Model):
    user = models.OneToOneField(User,on_delete=models.CASCADE,primary_key=True,)
    phone_number = models.IntegerField()
    company_name = models.CharField(max_length=256)

serializer.py(原有问题版本)

class UserSerializer(serializers.ModelSerializer):
    
    class Meta:
        model = User
        fields = '__all__'
class ProfileSerializer(serializers.ModelSerializer):
    user = UserSerializer(many=True)

    class Meta:
        model = Profile
        fields = '__all__'

    def create(self, validated_data):
        users_data = validated_data.pop('user')
        user = User.objects.create(**user_data)
        profile = Profile.objects.create(user=user,**validated_data)
        # for user_data in users_data:
            # User.objects.create(**user_data)
        return profile

第一步:修复序列化器基础问题

因为Profile和User是一对一关联,所以ProfileSerializer里的user字段不能设置many=True,否则会导致序列化/反序列化错误,修正后:

class ProfileSerializer(serializers.ModelSerializer):
    # 去掉many=True,适配一对一关系
    user = UserSerializer()

    class Meta:
        model = Profile
        fields = '__all__'

第二步:完善序列化器的CRUD方法

1. 修正Create方法逻辑

原有代码中变量名和数据结构不匹配,修正后:

def create(self, validated_data):
    # 取出嵌套的单个用户数据
    user_data = validated_data.pop('user')
    # 创建User实例
    user = User.objects.create(**user_data)
    # 创建Profile并关联User
    profile = Profile.objects.create(user=user, **validated_data)
    return profile

2. 实现Update方法

支持同时更新关联的User数据和Profile自身数据:

def update(self, instance, validated_data):
    # 取出嵌套用户数据(可选,不存在则跳过更新)
    user_data = validated_data.pop('user', None)
    
    # 更新Profile自身字段
    instance.phone_number = validated_data.get('phone_number', instance.phone_number)
    instance.company_name = validated_data.get('company_name', instance.company_name)
    instance.save()
    
    # 若有用户数据,更新关联的User实例
    if user_data:
        user = instance.user
        for attr, value in user_data.items():
            setattr(user, attr, value)
        user.save()
    
    return instance

3. 序列化器完整代码

整合后的serializer.py:

from rest_framework import serializers
from .models import User, Profile

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'

class ProfileSerializer(serializers.ModelSerializer):
    user = UserSerializer()

    class Meta:
        model = Profile
        fields = '__all__'

    def create(self, validated_data):
        user_data = validated_data.pop('user')
        user = User.objects.create(**user_data)
        profile = Profile.objects.create(user=user, **validated_data)
        return profile

    def update(self, instance, validated_data):
        user_data = validated_data.pop('user', None)
        
        # 更新Profile字段
        instance.phone_number = validated_data.get('phone_number', instance.phone_number)
        instance.company_name = validated_data.get('company_name', instance.company_name)
        instance.save()
        
        # 更新关联User字段
        if user_data:
            user = instance.user
            for attr, value in user_data.items():
                setattr(user, attr, value)
            user.save()
        
        return instance

第三步:编写视图类(实现单次API的完整CRUD)

使用ModelViewSet快速生成包含列表、详情、创建、更新、删除的API:

from rest_framework import viewsets
from .models import Profile
from .serializers import ProfileSerializer

class ProfileViewSet(viewsets.ModelViewSet):
    queryset = Profile.objects.all().select_related('user')  # 预加载User,避免N+1查询
    serializer_class = ProfileSerializer

第四步:配置URL路由

在项目urls.py中注册视图集:

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ProfileViewSet

router = DefaultRouter()
router.register(r'profiles', ProfileViewSet)

urlpatterns = [
    path('', include(router.urls)),
]

CRUD操作测试示例

1. 创建(POST)

请求URL:/profiles/
请求体(JSON):

{
    "user": {
        "username": "john_doe",
        "password": "secure123",
        "firstname": "John",
        "lastname": "Doe",
        "email": "john@example.com",
        "role": "staff"
    },
    "phone_number": 1234567890,
    "company_name": "Example Corp"
}

2. 查询列表(GET)

请求URL:/profiles/
返回结果包含所有Profile及其关联的User数据。

3. 查询详情(GET)

请求URL:/profiles/<profile_id>/(profile_id为关联User的ID)

4. 更新(PUT/PATCH)

请求URL:/profiles/<profile_id>/
请求体(JSON,PUT需传全量字段,PATCH可传部分):

{
    "user": {
        "email": "john.updated@example.com"
    },
    "phone_number": 9876543210
}

5. 删除(DELETE)

请求URL:/profiles/<profile_id>/
删除Profile时,关联的User会因on_delete=models.CASCADE被同步删除。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 04:48:20