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

如何将原始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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 07:13:15