针对“课程列表”与“课程详情”的api的写法
前端vue的项目在这里
表结构的设计 —— 课程、课程详细、章节
from django.db import models class Course(models.Model): """ 课程表 """ title = models.CharField(verbose_name='课程名称',max_length=32) course_img = models.CharField(verbose_name='课程图片',max_length=64) level_choices = ( (1,'初级'), (2,'中级'), (3,'高级'), ) level = models.IntegerField(verbose_name='课程难易程度',choices=level_choices,default=1) def __str__(self): return self.title
class CourseDetail(models.Model): """ 课程详细 """ course = models.OneToOneField(to='Course') slogon = models.CharField(verbose_name='口号',max_length=255) why = models.CharField(verbose_name='为什么要学?',max_length=255)
# 注意这么设计的话需要加上related_name,否则反向查询的时候会有问题 recommend_courses = models.ManyToManyField(verbose_name='推荐课程',to='Course',related_name='rc') def __str__(self): return "课程详细:"+self.course.title
class Chapter(models.Model): """ 章节 """ num = models.IntegerField(verbose_name='章节') name = models.CharField(verbose_name='章节名称',max_length=32) course = models.ForeignKey(verbose_name='所属课程',to='Course') def __str__(self): return self.name
在admin中录入数据
先注册
创建超级用户
python manage.py createsuperuser
进入admin页面录入数据
xxx
课程列表接口与课程详情接口的写法 *****
路由的写法
由于需要进行“版本控制”,并且做了路由的分发,我们在项目的主路由中加上版本进行分发:
from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^api/(?P<version>\w+)/', include('api.urls')), ]
然后在api应用中写具体路由(这里用到了ViewSetMixin,注意写法):
from django.conf.urls import url,include from api.views import course urlpatterns = [ # 方式一 # url(r'^course/$', course.CourseView.as_view()), # url(r'^course/(?P<pk>\d+)/$', course.CourseView.as_view()), # 方式二
# 获取所有数据用list方法 url(r'^course/$', course.CourseView.as_view({'get':'list'})), # 获取单个数据,传pk,用retrieve方法 url(r'^course/(?P<pk>\d+)/$', course.CourseView.as_view({'get':'retrieve'})), url(r'^test$', course.test), ]
序列化类
from api import models from rest_framework import serializers class CourseSerializer(serializers.ModelSerializer): """ 课程序列化 """
# level显示中文,用get_xxx_display方法 level = serializers.CharField(source='get_level_display')
# 注意Meta中需要指定model与展示的字段fields——包括上面的自定义字段 class Meta: model = models.Course fields = ['id','title','course_img','level']
class CourseDetailSerializer(serializers.ModelSerializer): """ 课程详细序列化 """ # one2one/fk/choice
# 一对一关系展示信息而不是具体的id —— 用source,注意这里用“跨表” title = serializers.CharField(source='course.title') img = serializers.CharField(source='course.course_img')
# 注意choices用的是 get_xxx_display,这里不加括号 level = serializers.CharField(source='course.get_level_display') # 推荐课程与章节,多对多关系展示信息而不是具体的id —— 不推荐用depth,因为depth把所有的数据都查出来了~不方便自定制 recommends = serializers.SerializerMethodField() chapter = serializers.SerializerMethodField()
# 注意Meta中必须指定model与要展示的字段——包括上面的自定义字段 class Meta: model = models.CourseDetail fields = ['course','title','img','level','slogon','why','recommends','chapter'] def get_recommends(self,obj): # 获取推荐的所有课程 —— 自己定制返回的个数与内容
# 这里的obj就是CourseDetail对象 —— 基于对象的正向查询 queryset = obj.recommend_courses.all() return [{'id':row.id,'title':row.title} for row in queryset] def get_chapter(self,obj): # 获取所有的章节 —— 自己定制返回的个数与内容
# 这里的obj就是CourseDetail对象 —— 基于对象的连续跨表查询 queryset = obj.course.chapter_set.all() return [{'id':row.id,'name':row.name} for row in queryset]
视图函数
from rest_framework.views import APIView from rest_framework.response import Response from api import models from rest_framework.viewsets import GenericViewSet,ViewSetMixin from api.serializers.course import CourseSerializer,CourseDetailSerializer # 继承ViewSetMixin class CourseView(ViewSetMixin,APIView): # 获取所有数据用list方法! def list(self,request,*args,**kwargs): """ 课程列表接口 :param request: :param args: :param kwargs: :return: """ ret = {'code':1000,'data':None} try: queryset = models.Course.objects.all()
# 所有数据,需要加 many=True ser = CourseSerializer(instance=queryset,many=True) ret['data'] = ser.data except Exception as e: ret['code'] = 1001 ret['error'] = '获取课程失败' return Response(ret)
# 获取单个数据用retrieve方法! def retrieve(self,request,*args,**kwargs): """ 课程详细接口 :param request: :param args: :param kwargs: :return: """ ret = {'code': 1000, 'data': None} try: # 获取课程ID pk = kwargs.get('pk') # 课程详细对象
# 注意这里是“跨表查询” —— 正向查询:course_id obj = models.CourseDetail.objects.filter(course_id=pk).first() # 由于是单个数据,这里不用加 many=True ser = CourseDetailSerializer(instance=obj) ret['data'] = ser.data except Exception as e: ret['code'] = 1001 ret['error'] = '获取课程失败' return Response(ret) # test —— 一对一跨表查询 def test(request,*args,**kwargs): from django.shortcuts import HttpResponse obj = models.Course.objects.filter(id=2).first() print(obj.title) print(obj.level) # print(obj.get_level_display() ) # return HttpResponse('...')
~~~