基于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
相关产品推荐
相关产品推荐

