Django自定义接口与DRF开发对比:手动实现JSON序列化与视图处理
本文详细解析在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使用区别的介绍即为核心内容,供读者参考。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













