如何将原始SQL查询响应传入Serializer类,并实现对应模型的数据新增与保存?
问题
我尝试使用原始SQL查询获取数据,但在将原始SQL查询响应传入Serializer类时遇到问题。
当前Serializer类代码如下:
class User_Serializer(serializers.ModelSerializer): class Meta: model = Users fields = '__all__'
视图类代码如下:
class UserView(APIView): def get(self, request, emailId, format=None): with connection.cursor() as cursor: cursor.execute("SELECT * FROM users") resRow = cursor.fetchone() serializerResponse = User_Serializer(resRow) return Response(serializerResponse.data)
我发现在此场景下ModelSerializer无法正常工作,请问应如何构建Serializer类,使其既能处理原始SQL查询结果,又能实现对应模型的数据新增(POST)与保存功能?
解决方案
首先得搞明白为啥ModelSerializer不好使:它是专门为Django的模型实例设计的,而你用原始SQL查出来的resRow是个元组,根本不是Users模型的实例,自然没法被它序列化。要同时搞定原始SQL结果的序列化和模型的新增保存,有两种靠谱的方法:
方法一:用普通Serializer类,自己搞定序列化和反序列化
直接继承serializers.Serializer,手动声明所有字段,这样既能处理SQL返回的字典/元组,也能处理POST请求的新增逻辑,灵活性拉满:
from rest_framework import serializers from .models import Users class UserSerializer(serializers.Serializer): # 照着Users模型的字段来声明,类型要匹配 id = serializers.IntegerField(read_only=True) email = serializers.EmailField() username = serializers.CharField(max_length=100) # 把你模型里的其他字段都补上 def create(self, validated_data): # POST请求时,用验证后的数据创建模型实例并保存 return Users.objects.create(**validated_data) def update(self, instance, validated_data): # 如果需要支持更新功能,就实现这个方法 instance.email = validated_data.get('email', instance.email) instance.username = validated_data.get('username', instance.username) # 其他字段同理更新 instance.save() return instance
然后修改你的视图类,把SQL返回的元组转成字典(这样序列化器才能识别字段):
from django.db import connection from rest_framework.views import APIView from rest_framework.response import Response from .serializers import UserSerializer class UserView(APIView): def get(self, request, emailId, format=None): with connection.cursor() as cursor: # 建议明确指定字段,避免返回多余数据,也能保证和序列化器字段对应 cursor.execute("SELECT id, email, username FROM users WHERE email = %s", [emailId]) # 获取查询结果的字段名列表 columns = [col[0] for col in cursor.description] resRow = cursor.fetchone() if resRow: # 把元组转成键值对字典 user_data = dict(zip(columns, resRow)) serializer = UserSerializer(user_data) return Response(serializer.data) return Response({"message": "User not found"}, status=404) def post(self, request, format=None): serializer = UserSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=201) return Response(serializer.errors, status=400)
方法二:把SQL结果转成模型实例(推荐,适合单条记录查询)
如果你的SQL查的是单条用户记录,可以把结果转成Users模型的实例,这样就能继续用你原来的ModelSerializer,不用重新写字段:
from django.db import connection from rest_framework.views import APIView from rest_framework.response import Response from .models import Users from .serializers import User_Serializer class UserView(APIView): def get(self, request, emailId, format=None): with connection.cursor() as cursor: cursor.execute("SELECT * FROM users WHERE email = %s", [emailId]) resRow = cursor.fetchone() if resRow: # 获取Users模型的所有字段名 field_names = [f.name for f in Users._meta.fields] # 把元组转成字典,创建模型实例(不用调用save(),因为是从数据库查的) user_instance = Users(**dict(zip(field_names, resRow))) # 设置主键,让Django知道这是已存在的实例,不是新的 user_instance.pk = resRow[0] serializer = User_Serializer(user_instance) return Response(serializer.data) return Response({"message": "User not found"}, status=404) def post(self, request, format=None): serializer = User_Serializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=201) return Response(serializer.errors, status=400)
这种方法的好处是复用现有代码,不用重新定义序列化器字段,但只适合SQL查询结果和模型字段完全匹配的场景。
小提醒
- 写原始SQL时,尽量明确指定字段,别用
SELECT *,这样既能减少数据传输,也能避免字段不匹配的问题。 - 如果是批量查询(用
fetchall()),方法一可以直接序列化列表,方法二需要循环创建多个模型实例。
内容的提问来源于stack exchange,提问作者Surajeet Das
相关产品推荐
相关产品推荐

