如何在Django REST API单次请求中更新两个关联模型表字段
单次请求更新关联User与Address表并返回指定格式响应
前提假设
基于Django + Django REST Framework实现,以下是完整的代码解决方案:
1. 模型定义(models.py)
确保User与Address的外键关联正确,通过related_name='addresses'实现用户地址的反向查询:
from django.db import models from django.contrib.auth.models import AbstractUser class User(AbstractUser): first_name = models.CharField(max_length=100) last_name = models.CharField(max_length=100) profile_picture = models.ImageField(upload_to='profile_pictures/', blank=True, null=True) date_of_birth = models.DateField(blank=True, null=True) gender = models.CharField(max_length=10, choices=[('male', 'Male'), ('female', 'Female'), ('other', 'Other')]) email = models.EmailField(unique=True) phone_number = models.CharField(max_length=20) class Address(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='addresses') street = models.CharField(max_length=255) city = models.CharField(max_length=100) state = models.CharField(max_length=100) country = models.CharField(max_length=100) zip_code = models.CharField(max_length=20)
2. 序列化器实现(serializers.py)
核心通过嵌套序列化器+自定义update方法,同时处理用户基本信息和关联地址的批量更新:
from rest_framework import serializers from .models import User, Address class AddressSerializer(serializers.ModelSerializer): class Meta: model = Address fields = ['street', 'city', 'state', 'country', 'zip_code'] class UserSerializer(serializers.ModelSerializer): addresses = AddressSerializer(many=True) class Meta: model = User fields = ['first_name', 'last_name', 'profile_picture', 'date_of_birth', 'username', 'gender', 'email', 'phone_number', 'addresses'] extra_kwargs = { 'username': {'required': False} # 允许username为空值 } def update(self, instance, validated_data): # 分离地址数据与用户基本数据 addresses_data = validated_data.pop('addresses', []) # 更新用户基本字段 for attr, value in validated_data.items(): setattr(instance, attr, value) instance.save() # 处理地址更新:采用「删除旧地址+创建新地址」逻辑,若需更新现有地址需传递address_id参数 instance.addresses.all().delete() for addr_data in addresses_data: Address.objects.create(user=instance, **addr_data) return instance
3. 视图编写(views.py)
实现PUT接口,处理单个用户的更新请求:
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from .models import User from .serializers import UserSerializer class UserProfileUpdateView(APIView): def put(self, request, pk): try: user = User.objects.get(pk=pk) except User.DoesNotExist: return Response({"error": "用户不存在"}, status=status.HTTP_404_NOT_FOUND) serializer = UserSerializer(user, data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
4. 路由配置(urls.py)
添加更新接口的路由映射:
from django.urls import path from .views import UserProfileUpdateView urlpatterns = [ path('users/<int:pk>/update/', UserProfileUpdateView.as_view(), name='user-profile-update'), ]
5. 测试请求
使用PUT方法调用接口,请求体格式完全匹配你给出的示例JSON:
curl -X PUT http://127.0.0.1:8000/users/1/update/ \ -H "Content-Type: application/json" \ -d '{ "first_name": "abijith", "last_name": "manu", "profile_picture": "http://127.0.0.1:8000/media/profile_pictures/my_pic_RxnXQ6n.jpg", "date_of_birth": "2024-02-16", "username": "", "gender": "male", "email": "doc@gmail.com", "phone_number": "7306986870", "addresses": [ { "street": "xvsvf", "city": "sss", "state": "ssss", "country": "ggggggggg", "zip_code": "sssssss" } ] }'
接口返回的响应格式将与你要求的完全一致。
内容的提问来源于stack exchange,提问作者Ajith Ajayan
相关产品推荐
相关产品推荐

