使用Django REST Framework创建供应商函数时遇问题求助
问题描述
我是一名Flask开发者,当前正在使用Django开发项目。采用Firebase进行认证,使用Django REST Framework整合时遇到问题:尝试为用户创建供应商时未成功,返回结果不符合预期。
请求详情
- 请求地址:
http://localhost:8000/pm/createsupplier/3/ - 请求体:
{ "supplier": {"name": "Donald Duck", "phone": 111, "email": "donald@yahoo.com"} }
- 响应结果:
{ "email": "kbess86@gmail.com" }
相关代码
models.py
class UserProfile(models.Model): user = models.OneToOneField(User,on_delete=models.CASCADE) bio = models.CharField(max_length=200) email = models.CharField(max_length=200) class Supplier(models.Model): user = models.ForeignKey(UserProfile, on_delete=models.CASCADE) name = models.CharField(max_length=200) phone = models.IntegerField() email = models.EmailField()
views.py
class createsuppliers(viewsets.ModelViewSet): queryset = UserProfile.objects.all() serializer_class = CreateSupplierSerializer lookup_field = 'user'
serializers.py
class CreateSupplierSerializer(serializers.ModelSerializer): name = serializers.CharField(required=False, allow_blank=True, max_length=100) email = serializers.CharField(required=False, allow_blank=True, max_length=100) phone = serializers.IntegerField(required=False) def create(self, instance, validated_data): supplier_data = validated_data.pop('supplier') supplier = Supplier.objects.create(user=instance, **supplier_data) return supplier class Meta: model=Supplier fields=['name','email','phone']
问题分析与修复
1. 视图类逻辑错误
当前createsuppliers继承ModelViewSet但用法错误:
lookup_field设为user,但UserProfile的主键是id,URL中的3是UserProfile的id,导致视图无法正确定位实例。ModelViewSet的默认create方法用于创建新的UserProfile,但需求是给已存在的UserProfile创建关联Supplier,应该改用自定义动作。
修改views.py:
from rest_framework import viewsets, status from rest_framework.response import Response class createsuppliers(viewsets.ViewSet): queryset = UserProfile.objects.all() def create_supplier(self, request, pk=None): # 获取对应的UserProfile实例 user_profile = self.get_object() # 传入请求数据和上下文 serializer = CreateSupplierSerializer(data=request.data, context={'user_profile': user_profile}) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
同时在urls.py中配置路由:
path('pm/createsupplier/<int:pk>/', createsuppliers.as_view({'post': 'create_supplier'})),
2. 序列化器核心错误
create方法签名错误:ModelSerializer的create方法应为def create(self, validated_data),你写成了def create(self, instance, validated_data)(这是update方法的签名)。- 未正确处理嵌套的
supplier字段,需要定义嵌套序列化器来接收请求体中的结构。 - 序列化器字段与模型不匹配:
Supplier的email是EmailField,序列化器用了CharField;name的max_length模型是200,序列化器设为100,且不必要地设置了required=False。
修改serializers.py(支持嵌套请求体):
class SupplierSerializer(serializers.ModelSerializer): class Meta: model = Supplier fields = ['name', 'email', 'phone'] extra_kwargs = { 'name': {'max_length': 200, 'required': True}, 'email': {'required': True}, 'phone': {'required': True} } class CreateSupplierSerializer(serializers.Serializer): supplier = SupplierSerializer() def create(self, validated_data): supplier_data = validated_data.pop('supplier') # 从上下文获取UserProfile实例 user_profile = self.context['user_profile'] return Supplier.objects.create(user=user_profile, **supplier_data)
如果不需要嵌套结构,可简化序列化器,请求体直接传供应商字段:
class CreateSupplierSerializer(serializers.ModelSerializer): class Meta: model = Supplier fields = ['name', 'email', 'phone'] extra_kwargs = { 'name': {'max_length': 200, 'required': True}, 'email': {'required': True}, 'phone': {'required': True} } def create(self, validated_data): user_profile = self.context['user_profile'] return Supplier.objects.create(user=user_profile, **validated_data)
此时请求体改为:
{"name": "Donald Duck", "phone": 111, "email": "donald@yahoo.com"}
3. 响应异常原因
之前返回UserProfile的email,是因为视图的queryset是UserProfile,ModelViewSet默认返回的是UserProfile实例数据,而非创建的Supplier数据。修改后的视图会返回正确的供应商信息。
内容的提问来源于stack exchange,提问作者Kyle Andrew
相关产品推荐
相关产品推荐

