1. 程式人生 > 程式設計 >淺談django不使用restframework自定義介面與使用的區別

淺談django不使用restframework自定義介面與使用的區別

django可以使用restframework快速開發介面,返回前端所需要的json資料,但是有時候利用restframework開發的介面並不能滿足所有的需求,這時候就需要自己手動開發介面,也就是將需要用到的某些物件轉化為需要使用的json資料,今天記錄一下django自己定義介面的一種方法與思路

假設我們定義三張資料表,分別是問卷,問題,選項。一張問卷包含不同的問題,一個問題可以設定不同的選項,自定義的介面可以實現檢視所有或單個問卷的標題與id,可以檢視所有或單個問題的所屬問卷,問題標題,問卷的選項。

1.定義我們需要的模型類,並且在對應的模型類中定義對應的將物件轉化為字典的函式

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()來檢視當前問卷的所有問題。

2.定義類檢視

(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,questionnaire_id):
 questionnaire = Questionnaire.objects.get(id=questionnaire_id)
 data = questionnaire.questionnaire_to_dict()
 return JsonResponse(data)

這裡繼承View類自己定義get方法與post方法處理請求,首先獲取到所有的問卷物件,在將每一個問卷物件通過自定義的函式轉化為字典,最後返回json資料,同樣處理post請求新增問卷時,首先獲取到問卷的標題,然後例項化一個問卷的物件,再將問卷物件儲存。獲取單個問卷物件通過傳遞的id檢視到指定的問卷物件,再通過自定義的函式將物件轉化為字典資料,最後返回單個問卷物件的json資料。

(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,**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,question_id):
 question = Question.objects.get(id=question_id)
 question.delete()
 
 def put(self,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,question_id):
 question = Question.objects.get(id=question_id)
 data = question.question_to_dict()
 return JsonResponse(data)

這裡難點是使用put方法修改某個物件的資料,使用put請求,將需要修改的資料寫成json格式,並把修改後的資料重新賦值給物件,然後儲存。

3.配置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來開發介面的程式碼

1.建立對應的序列化類

from rest_framework import serializers
from question.models import Question,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.定義類檢視

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,pk):
 questionnaire = self.get_object(pk)
 serializer = QuestionnaireSerializer(questionnaire)
 return Response(serializer.data)
 
 def put(self,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,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,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(),url(r'^questionnaire/(?P<pk>\d+)/$',Questionnaire_Detail.as_view(),QuestionnaireList.as_view(),]

這裡我只定義了獲取所有問卷,單個問卷及所有問題的類,使用restframework開發介面雖然快速,程式碼易懂,但是它的缺點在於通過序列化類只能返回這個模型類本身的欄位,並不能返回它所關聯的外來鍵屬性的欄位,要想獲取其他關聯模型類的資料就得定義另外的類檢視,那麼對應的url也需要配置。但是同樣它的好處在於快速,程式碼簡潔易懂,只不過是獲取不同模型類的資料需要定義不同的介面,不能像自定義介面那樣定義一個介面可以獲得其他模型類的資料。

以上這篇淺談django不使用restframework自定義介面與使用的區別就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。