Django自定义接口与DRF开发对比:手动实现JSON序列化与视图处理

闻溪
闻溪
发布时间:2026-10-14| 4人浏览过
原创

本文详细解析在Django中不使用RestFramework手动开发接口的完整流程,涵盖模型字典转换、View类继承及URL配置。通过对比DRF序列化器机制,指出手动方式虽代码简洁但关联数据获取复杂,而DRF虽高效但需额外定义接口。文章提供问卷、问题及选项模型的完整代码示例,帮助开发者根据需求选择合适方案。

Django手动接口开发概述

Django框架支持利用RestFramework快速构建接口并返回前端所需的JSON数据。然而,在某些场景下,RestFramework的功能可能无法完全覆盖所有业务需求,此时需要手动开发接口。具体做法是将特定对象转换为所需的JSON格式。本文旨在记录一种Django手动定义接口的实现方法与核心思路。

假设系统包含三张数据表:问卷、问题和选项。一张问卷可包含多个问题,每个问题可设置多个选项。自定义接口需实现以下功能:查看或获取单个问卷的标题与ID;查看或获取单个问题的所属问卷、问题标题及该问题下的所有选项。

手动实现接口的核心步骤

第一步是定义所需的模型类,并在对应的模型类中编写将对象转换为字典的函数。


from django.db import models
 
class Questionnaire(models.Model):
 '''问卷'''
 title = models.CharField('标题',max_length=100)
 class Meta:
 verbose_name_plural = '所有问卷'
 def questionnaire_to_dict(self):
 '''把questionnaire对象转化为字典'''
 return dict(questionnaire_id=self.id,title=self.title,questions=[question.question_to_dict() for question in self.questions.all()])
 def __str__(self):
 return self.title
 
class Question(models.Model):
 '''问题'''
 #所属问卷
 questionnaire = models.ForeignKey(Questionnaire,verbose_name='所属问卷',related_name='questions')
 #问题标题
 title = models.CharField('问题',max_length=150)
 #是否是多选
 is_checkbox = models.BooleanField('是否多选',default=False,help_text='是否是多选问题')
 class Meta:
 verbose_name_plural = '问题'
 
 def question_to_dict(self):
 '''把question对象转化为字典'''
 return dict(title=self.title,choice=[choice.choice_to_dict() for choice in self.choices.all()],
   is_checkbox=self.is_checkbox,questionnaire_id=self.questionnaire.id)
 
 def __str__(self):
 return self.title
 
class Choice(models.Model):
 '''选项'''
 #所属的问题
 question = models.ForeignKey(Question,verbose_name='所属问题',related_name='choices')
 content = models.CharField('选项内容',max_length=150)
 
 class Meta:
 verbose_name_plural = '问题选项'
 
 def choice_to_dict(self):
 '''把choice对象转化为字典'''
 #选项id,选项所属的问题id,选项内容
 return dict(id=self.id,question_id=self.question.id,content=self.content)
 
 def __str__(self):
 return self.content

在转换函数中,需将需要序列化的字段添加进去。当涉及外键时,通过指定“related_name”属性来定义关系名,以便进行反向查找。例如,若问卷模型类中未直接包含question字段,但在Question模型类中指定questionnaire外键时设置了related_name='questions',则可通过self.questions.all()获取当前问卷关联的所有问题。

第二步是定义类视图(View Class)。

(1) 定义用于查看所有问卷列表及添加新问卷的类视图。


from question.models import Question,Questionnaire,Choice
from django.http import JsonResponse
from django.views import View
import json
class Questionnaires(View):
 def get(self,request):
 #获取所有问卷
 data = []
 questionnaires = Questionnaire.objects.all() #获取所有的问卷类
 for questionnaire in questionnaires:
  data.append(questionnaire.questionnaire_to_dict())
 return JsonResponse({'data':data})
 
 def post(self,request,*args,**kwargs):
 data = json.loads(request.body.decode())
 questionnaire = Questionnaire(title=data.get('title'))
 questionnaire.save()
 return JsonResponse({'msg':'success save'})
 
class QuestionnaireDetail(View):
 '''获取id为questionnaire_id的问卷'''
 def get(self,request,questionnaire_id):
 questionnaire = Questionnaire.objects.get(id=questionnaire_id)
 data = questionnaire.questionnaire_to_dict()
 return JsonResponse(data)

此处继承View类,分别定义get和post方法来处理HTTP请求。首先获取所有问卷对象,遍历每个对象并通过自定义函数将其转换为字典,最后返回JSON数据。对于添加问卷的post请求,首先从请求中获取问卷标题,实例化一个问卷对象,保存该对象后返回结果。若需获取单个问卷,通过传递的ID查询指定对象,再经自定义函数转换为字典后返回。

(2) 实现获取所有问题对象数据及添加问题的功能。


class Questions(View):
 def get(self,request):
 #查询所有问题
 questions_set = Question.objects.all()
 #把question_set转化为字典
 data = []
 for question in questions_set:
  data.append(question.question_to_dict())
 #把字典数据当做json返回
 return JsonResponse({'data':data})
 def post(self,request,*args,**kwargs):
 '''假设前端通过post传过来一个json数据'''
 #把request中的json转化为python对象
 data = json.loads(request.body.decode())
 #抽取数据
 questionnaire_id = data.get('questionnaire_id')
 title = data.get('title')
 is_checkbox = data.get('is_checkbox')
 # 获取questionnaire_id对应的对象
 questionnaire = Questionnaire.objects.get(id=questionnaire_id)
 #创建Question实例
 question = Question(title=title,is_checkbox=is_checkbox,questionnaire=questionnaire)
 question.save()
 #创建choice对象
 choices = data.get('choice')
 for c in choices:
  choice = Choice()
  choice.content = c
  choice.question = question
  choice.save()
 return JsonResponse({"msg":"success save"})

通过get请求接收并返回所有问题的JSON数据。利用post方法从前端接收传递的JSON数据,将其转换为对象实例并保存。保存成功后,返回相应的提示信息。

(3) 使用get、put和delete方法处理单个问题对象的增删改查。


class QuestionDetail(View):
 def delete(self,request,question_id):
 question = Question.objects.get(id=question_id)
 question.delete()
 
 def put(self,request,question_id):
 #获取前端put的数据
 data = json.loads(request.body.decode())
 title = data.get('title')
 #获取question对象
 question = Question.objects.get(id=question_id)
 question.title = title
 question.save()
 return JsonResponse({'msg':'modify success'})
 
 def get(self,request,question_id):
 question = Question.objects.get(id=question_id)
 data = question.question_to_dict()
 return JsonResponse(data)

此处的难点在于使用put方法修改对象数据。通过put请求接收前端提交的JSON格式数据,将修改后的值重新赋值给对象属性,随后调用save方法保存更改。

第三步是配置URL路由,以便调用上述接口。


from django.conf.urls import url
from question.views import Questions,Questionnaires,QuestionDetail,QuestionnaireDetail
urlpatterns = [
 url(r'^questions/$',Questions.as_view(),name='questions'),
 url(r'^questionnaire/(?P<questionnaire_id>\d+)/$',QuestionnaireDetail.as_view(),name='questionnaire'),
 url(r'^questionnaires/$',Questionnaires.as_view(),name='questionnaires'),
 
 url(r'^question/(?P<question_id>\d+)/$',QuestionDetail.as_view(),name='question'),
]

RestFramework开发方式对比

相比之下,我们也可以使用RestFramework快速开发接口。以下展示了使用RestFramework开发接口的代码示例。

1. 创建对应的序列化类(Serializers)。


from rest_framework import serializers
from question.models import Question,Questionnaire,Choice
 
class QuestionnaireSerializer(serializers.ModelSerializer):
 class Meta:
 model = Questionnaire
 fields = ('title',)
 
class QuestionSerializer(serializers.ModelSerializer):
 class Meta:
 model = Question
 fields = ('title','is_checkbox','questionnaire')
 
class ChoiceSerializer(serializers.ModelSerializer):
 class Meta:
 model = Choice
 fields = ('content','question')

利用这些序列化类来处理所需字段的序列化工作。

2. 定义类视图(Views)。


class QuestionnaireList(APIView):
 def get(self,request):
 questionnaire = Questionnaire.objects.all()
 serializer = QuestionnaireSerializer(questionnaire,many=True)
 return Response(serializer.data)
 
 def post(self,request):
 serializer = QuestionnaireSerializer(data=request.data)
 if serializer.is_valid():
  serializer.save()
  return Response(serializer.data)
 return Response(serializer.errors)
 
class Questionnaire_Detail(APIView):
 def get_object(self,pk):
 try:
  return Questionnaire.objects.get(pk=pk)
 except Questionnaire.DoesNotExist:
  raise Http404
 def get(self,request,pk):
 questionnaire = self.get_object(pk)
 serializer = QuestionnaireSerializer(questionnaire)
 return Response(serializer.data)
 
 def put(self,request,pk):
 questionnaire = self.get_object(pk)
 serializer = QuestionSerializer(questionnaire,data=request.data)
 if serializer.is_valid():
  serializer.save()
  return Response(serializer.data)
 return Response(serializer.errors)
 
 def delete(self,request,pk):
 questionnaire = self.get_object(pk)
 questionnaire.delete()
 return Response(status=status.HTTP_204_NO_CONTENT)
 
class QuestionList(APIView):
 def get(self,request):
 question = Question.objects.all()
 serializer = QuestionSerializer(question,many=True)
 return Response(serializer.data)
 
 def post(self,request):
 serializer = QuestionSerializer(data=request.data)
 if serializer.is_valid():
  serializer.save()
  return Response(serializer.data)
 return Response(serializer.errors)

3. 配置URL路由。


from django.conf.urls import url
from question.views import Questionnaire_Detail,QuestionnaireList,QuestionList
urlpatterns = [
 url(r'^questions/$',QuestionList.as_view(),name='questions'),
 url(r'^questionnaire/(?P<pk>\d+)/$',Questionnaire_Detail.as_view(),name='questionnaire'),
 url(r'^questionnaires/$',QuestionnaireList.as_view(),name='questionnaires'),
]

在上述示例中,仅定义了获取所有问卷、单个问卷及所有问题的类。虽然RestFramework开发接口速度快且代码简洁易懂,但其缺点在于序列化器仅能返回模型类本身的字段,无法直接返回关联外键属性的字段。若需获取其他关联模型的数据,必须定义额外的类视图并配置对应的URL。然而,其优势在于开发效率高、代码简洁,代价是获取不同模型类数据时需定义多个接口,无法像手动自定义接口那样通过单一接口获取关联模型数据。

以上关于Django不使用RestFramework自定义接口及其与DRF使用区别的介绍即为核心内容,供读者参考。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。