昨日内容回顾

  1. 1. 为什么要做前后端分离?
  2. - 前后端交给不同的人来编写,职责划分明确。
  3. - API (IOS,安卓,PC,微信小程序...)
  4. - vue.js等框架编写前端时,会比之前写jQuery更简单快捷。
  5. 2. 简述http协议?
  6. - 基于socket
  7. - 数据格式:
  8. "GET /index?name=123&age=19 http1.1\r\nhost:www.luffyciti.com\r\ncontent-type:application/json...\r\n\r\n"
  9. "POST /index http1.1\r\nhost:www.luffyciti.com\r\ncontent-type:application/json...\r\n\r\n{name:'alex',age:18}"
  10. "POST /index http1.1\r\nhost:www.luffyciti.com\r\ncontent-type:application/enform.....\r\n\r\nname=alex&age=18&xx=19"
  11. - 无状态短链接
  12. 一次请求一次响应之后断开连接
  13. 3. 简述restful 规范?
  14. https://www.luffycity.com/api/v1/courses/?sub_category=0
  15. https://www.luffycity.com/api/v1/courses/?sub_category=0
  16. 看上面一段url,可以说出5
  17. 1. 使用https代替http 2.URL中体现自己写的是API 3. URL中体现版本 4. 使用名词 5.参数要合理
  18. 之后,请求方式,响应信息。可以说后面5
  19. 6. 根据请求方式不同,处理不同的操作 7.返回状态码 8.返回错误信息 9. 返回code 10.hyper link(超链接)
  20. 4. django rest framework组件的作用?
  21. - 快速实现符合restful 规范的api
  22. 5. 列举django rest framework组件(10个)?
  23. - 版本
  24. - 权限
  25. - 认证
  26. - 节流
  27. - 分页
  28. - 解析器
  29. - 序列化
  30. - 视图
  31. - 路由
  32. - 渲染器
  33. 6. 路飞的表结构
  34. a. 课程分类
  35. - 课程大类
  36. - 课程子类
  37. b. 学位课
  38. - 学位课
  39. - 奖学金
  40. - 老师
  41. c. 专题课 or 学位课模块
  42. - 专题课 or 学位课模块
  43. - 课程详细
  44. - 课程大纲
  45. - 常见问题
  46. - 章节
  47. - 课时
  48. - 作业
  49. d. 价格
  50. - 价格策略
  51. 7. django contenttypes组件的作用?
  52. 为了解决一张表和多个表做外键关联

上面都是面试题

列举django rest framework的10个组件,可以根据django请求生命周期来记

  1. 请求路径包含版本,请求先到达路由,2.进入组件。认证,权限,节流。3.到达视图,获取参数,使用解析器。4.获取数据库记录,做序列化返回。

5.数据太多,要做分页,返回给用户之后,要做渲染,利用渲染器

一、作业讲解

下面代码:

https://github.com/987334176/luffycity/archive/v1.zip

修改models.py

  1. from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
  2. from django.contrib.contenttypes.models import ContentType
  3. from django.db.models import Q
  4. from django.utils.safestring import mark_safe
  5. from django.db import models
  6. import hashlib
  7. # ######################## 课程相关 ########################
  8. class CourseCategory(models.Model):
  9. """课程大类, e.g 前端 后端..."""
  10. name = models.CharField(max_length=64, unique=True)
  11. def __str__(self):
  12. return "%s" % self.name
  13. class Meta:
  14. verbose_name_plural = "01.课程大类"
  15. class CourseSubCategory(models.Model):
  16. """课程子类, e.g python linux """
  17. category = models.ForeignKey("CourseCategory")
  18. name = models.CharField(max_length=64, unique=True)
  19. def __str__(self):
  20. return "%s" % self.name
  21. class Meta:
  22. verbose_name_plural = "02.课程子类"
  23. class DegreeCourse(models.Model):
  24. """学位课程"""
  25. name = models.CharField(max_length=128, unique=True)
  26. course_img = models.CharField(max_length=255, verbose_name="缩略图")
  27. brief = models.TextField(verbose_name="学位课程简介", )
  28. total_scholarship = models.PositiveIntegerField(verbose_name="总奖学金(贝里)", default=40000) # 2000 2000
  29. mentor_compensation_bonus = models.PositiveIntegerField(verbose_name="本课程的导师辅导费用(贝里)", default=15000)
  30. period = models.PositiveIntegerField(verbose_name="建议学习周期(days)", default=150) # 为了计算学位奖学金
  31. prerequisite = models.TextField(verbose_name="课程先修要求", max_length=1024)
  32. teachers = models.ManyToManyField("Teacher", verbose_name="课程讲师")
  33. # 用于GenericForeignKey反向查询, 不会生成表字段,切勿删除
  34. # coupon = GenericRelation("Coupon")
  35. # 用于GenericForeignKey反向查询,不会生成表字段,切勿删除
  36. degreecourse_price_policy = GenericRelation("PricePolicy")
  37. def __str__(self):
  38. return self.name
  39. class Meta:
  40. verbose_name_plural = "03.学位课"
  41. class Teacher(models.Model):
  42. """讲师、导师表"""
  43. name = models.CharField(max_length=32)
  44. role_choices = ((0, '讲师'), (1, '导师'))
  45. role = models.SmallIntegerField(choices=role_choices, default=0)
  46. title = models.CharField(max_length=64, verbose_name="职位、职称")
  47. signature = models.CharField(max_length=255, help_text="导师签名", blank=True, null=True)
  48. image = models.CharField(max_length=128)
  49. brief = models.TextField(max_length=1024)
  50. def __str__(self):
  51. return self.name
  52. class Meta:
  53. verbose_name_plural = "04.导师或讲师"
  54. class Scholarship(models.Model):
  55. """学位课程奖学金"""
  56. degree_course = models.ForeignKey("DegreeCourse")
  57. time_percent = models.PositiveSmallIntegerField(verbose_name="奖励档位(时间百分比)", help_text="只填百分值,如80,代表80%")
  58. value = models.PositiveIntegerField(verbose_name="奖学金数额")
  59. def __str__(self):
  60. return "%s:%s" % (self.degree_course, self.value)
  61. class Meta:
  62. verbose_name_plural = "05.学位课奖学金"
  63. class Course(models.Model):
  64. """专题课/学位课模块表"""
  65. name = models.CharField(max_length=128, unique=True)
  66. course_img = models.CharField(max_length=255)
  67. sub_category = models.ForeignKey("CourseSubCategory")
  68. course_type_choices = ((0, '付费'), (1, 'VIP专享'), (2, '学位课程'))
  69. course_type = models.SmallIntegerField(choices=course_type_choices)
  70. # 不为空;学位课的某个模块
  71. # 为空;专题课
  72. degree_course = models.ForeignKey("DegreeCourse", blank=True, null=True, help_text="若是学位课程,此处关联学位表")
  73. brief = models.TextField(verbose_name="课程概述", max_length=2048)
  74. level_choices = ((0, '初级'), (1, '中级'), (2, '高级'))
  75. level = models.SmallIntegerField(choices=level_choices, default=1)
  76. pub_date = models.DateField(verbose_name="发布日期", blank=True, null=True)
  77. period = models.PositiveIntegerField(verbose_name="建议学习周期(days)", default=7) #
  78. order = models.IntegerField("课程顺序", help_text="从上一个课程数字往后排")
  79. attachment_path = models.CharField(max_length=128, verbose_name="课件路径", blank=True, null=True)
  80. status_choices = ((0, '上线'), (1, '下线'), (2, '预上线'))
  81. status = models.SmallIntegerField(choices=status_choices, default=0)
  82. template_id = models.SmallIntegerField("前端模板id", default=1)
  83. # coupon = GenericRelation("Coupon")
  84. # 用于GenericForeignKey反向查询,不会生成表字段,切勿删除
  85. price_policy = GenericRelation("PricePolicy")
  86. asked_question = GenericRelation("OftenAskedQuestion")
  87. def __str__(self):
  88. return "%s(%s)" % (self.name, self.get_course_type_display())
  89. def save(self, *args, **kwargs):
  90. if self.course_type == 2:
  91. if not self.degree_course:
  92. raise ValueError("学位课程必须关联对应的学位表")
  93. super(Course, self).save(*args, **kwargs)
  94. class Meta:
  95. verbose_name_plural = "06.专题课或学位课模块"
  96. class CourseDetail(models.Model):
  97. """课程详情页内容"""
  98. course = models.OneToOneField("Course")
  99. hours = models.IntegerField("课时")
  100. course_slogan = models.CharField(max_length=125, blank=True, null=True)
  101. video_brief_link = models.CharField(verbose_name='课程介绍', max_length=255, blank=True, null=True)
  102. why_study = models.TextField(verbose_name="为什么学习这门课程")
  103. what_to_study_brief = models.TextField(verbose_name="我将学到哪些内容")
  104. career_improvement = models.TextField(verbose_name="此项目如何有助于我的职业生涯")
  105. prerequisite = models.TextField(verbose_name="课程先修要求", max_length=1024)
  106. recommend_courses = models.ManyToManyField("Course", related_name="recommend_by", blank=True)
  107. teachers = models.ManyToManyField("Teacher", verbose_name="课程讲师")
  108. def __str__(self):
  109. return "%s" % self.course
  110. class Meta:
  111. verbose_name_plural = "07.课程或学位模块详细"
  112. class OftenAskedQuestion(models.Model):
  113. """常见问题"""
  114. content_type = models.ForeignKey(ContentType) # 关联course or degree_course
  115. object_id = models.PositiveIntegerField()
  116. content_object = GenericForeignKey('content_type', 'object_id')
  117. question = models.CharField(max_length=255)
  118. answer = models.TextField(max_length=1024)
  119. def __str__(self):
  120. return "%s-%s" % (self.content_object, self.question)
  121. class Meta:
  122. unique_together = ('content_type', 'object_id', 'question')
  123. verbose_name_plural = "08. 常见问题"
  124. class CourseOutline(models.Model):
  125. """课程大纲"""
  126. course_detail = models.ForeignKey("CourseDetail")
  127. title = models.CharField(max_length=128)
  128. # 前端显示顺序
  129. order = models.PositiveSmallIntegerField(default=1)
  130. content = models.TextField("内容", max_length=2048)
  131. def __str__(self):
  132. return "%s" % self.title
  133. class Meta:
  134. unique_together = ('course_detail', 'title')
  135. verbose_name_plural = "09. 课程大纲"
  136. class CourseChapter(models.Model):
  137. """课程章节"""
  138. course = models.ForeignKey("Course")
  139. chapter = models.SmallIntegerField(verbose_name="第几章", default=1)
  140. name = models.CharField(max_length=128)
  141. summary = models.TextField(verbose_name="章节介绍", blank=True, null=True)
  142. pub_date = models.DateField(verbose_name="发布日期", auto_now_add=True)
  143. class Meta:
  144. unique_together = ("course", 'chapter')
  145. verbose_name_plural = "10. 课程章节"
  146. def __str__(self):
  147. return "%s:(第%s章)%s" % (self.course, self.chapter, self.name)
  148. class CourseSection(models.Model):
  149. """课时目录"""
  150. chapter = models.ForeignKey("CourseChapter")
  151. name = models.CharField(max_length=128)
  152. order = models.PositiveSmallIntegerField(verbose_name="课时排序", help_text="建议每个课时之间空1至2个值,以备后续插入课时")
  153. section_type_choices = ((0, '文档'), (1, '练习'), (2, '视频'))
  154. section_type = models.SmallIntegerField(default=2, choices=section_type_choices)
  155. section_link = models.CharField(max_length=255, blank=True, null=True, help_text="若是video,填vid,若是文档,填link")
  156. video_time = models.CharField(verbose_name="视频时长", blank=True, null=True, max_length=32) # 仅在前端展示使用
  157. pub_date = models.DateTimeField(verbose_name="发布时间", auto_now_add=True)
  158. free_trail = models.BooleanField("是否可试看", default=False)
  159. class Meta:
  160. unique_together = ('chapter', 'section_link')
  161. verbose_name_plural = "11. 课时"
  162. def __str__(self):
  163. return "%s-%s" % (self.chapter, self.name)
  164. class Homework(models.Model):
  165. chapter = models.ForeignKey("CourseChapter")
  166. title = models.CharField(max_length=128, verbose_name="作业题目")
  167. order = models.PositiveSmallIntegerField("作业顺序", help_text="同一课程的每个作业之前的order值间隔1-2个数")
  168. homework_type_choices = ((0, '作业'), (1, '模块通关考核'))
  169. homework_type = models.SmallIntegerField(choices=homework_type_choices, default=0)
  170. requirement = models.TextField(max_length=1024, verbose_name="作业需求")
  171. threshold = models.TextField(max_length=1024, verbose_name="踩分点")
  172. recommend_period = models.PositiveSmallIntegerField("推荐完成周期(天)", default=7)
  173. scholarship_value = models.PositiveSmallIntegerField("为该作业分配的奖学金(贝里)")
  174. note = models.TextField(blank=True, null=True)
  175. enabled = models.BooleanField(default=True, help_text="本作业如果后期不需要了,不想让学员看到,可以设置为False")
  176. class Meta:
  177. unique_together = ("chapter", "title")
  178. verbose_name_plural = "12. 章节作业"
  179. def __str__(self):
  180. return "%s - %s" % (self.chapter, self.title)
  181. # class CourseReview(models.Model):
  182. # """课程评价"""
  183. # enrolled_course = models.OneToOneField("EnrolledCourse")
  184. # about_teacher = models.FloatField(default=0, verbose_name="讲师讲解是否清晰")
  185. # about_video = models.FloatField(default=0, verbose_name="内容实用")
  186. # about_course = models.FloatField(default=0, verbose_name="课程内容通俗易懂")
  187. # review = models.TextField(max_length=1024, verbose_name="评价")
  188. # disagree_number = models.IntegerField(default=0, verbose_name="踩")
  189. # agree_number = models.IntegerField(default=0, verbose_name="赞同数")
  190. # tags = models.ManyToManyField("Tags", blank=True, verbose_name="标签")
  191. # date = models.DateTimeField(auto_now_add=True, verbose_name="评价日期")
  192. # is_recommend = models.BooleanField("热评推荐", default=False)
  193. # hide = models.BooleanField("不在前端页面显示此条评价", default=False)
  194. #
  195. # def __str__(self):
  196. # return "%s-%s" % (self.enrolled_course.course, self.review)
  197. #
  198. # class Meta:
  199. # verbose_name_plural = "13. 课程评价(购买课程后才能评价)"
  200. #
  201. #
  202. # class DegreeCourseReview(models.Model):
  203. # """学位课程评价
  204. # 为了以后可以定制单独的评价内容,所以不与普通课程的评价混在一起,单独建表
  205. # """
  206. # enrolled_course = models.ForeignKey("EnrolledDegreeCourse")
  207. # course = models.ForeignKey("Course", verbose_name="评价学位模块", blank=True, null=True,
  208. # help_text="不填写即代表评价整个学位课程", limit_choices_to={'course_type': 2})
  209. # about_teacher = models.FloatField(default=0, verbose_name="讲师讲解是否清晰")
  210. # about_video = models.FloatField(default=0, verbose_name="视频质量")
  211. # about_course = models.FloatField(default=0, verbose_name="课程")
  212. # review = models.TextField(max_length=1024, verbose_name="评价")
  213. # disagree_number = models.IntegerField(default=0, verbose_name="踩")
  214. # agree_number = models.IntegerField(default=0, verbose_name="赞同数")
  215. # tags = models.ManyToManyField("Tags", blank=True, verbose_name="标签")
  216. # date = models.DateTimeField(auto_now_add=True, verbose_name="评价日期")
  217. # is_recommend = models.BooleanField("热评推荐", default=False)
  218. # hide = models.BooleanField("不在前端页面显示此条评价", default=False)
  219. #
  220. # def __str__(self):
  221. # return "%s-%s" % (self.enrolled_course, self.review)
  222. #
  223. # class Meta:
  224. # verbose_name_plural = "14. 学位课评价(购买课程后才能评价)"
  225. class PricePolicy(models.Model):
  226. """价格与有课程效期表"""
  227. content_type = models.ForeignKey(ContentType) # 关联course or degree_course
  228. object_id = models.PositiveIntegerField()
  229. content_object = GenericForeignKey('content_type', 'object_id')
  230. # course = models.ForeignKey("Course")
  231. valid_period_choices = ((1, '1天'), (3, '3天'),
  232. (7, '1周'), (14, '2周'),
  233. (30, '1个月'),
  234. (60, '2个月'),
  235. (90, '3个月'),
  236. (180, '6个月'), (210, '12个月'),
  237. (540, '18个月'), (720, '24个月'),
  238. )
  239. valid_period = models.SmallIntegerField(choices=valid_period_choices)
  240. price = models.FloatField()
  241. class Meta:
  242. unique_together = ("content_type", 'object_id', "valid_period")
  243. verbose_name_plural = "15. 价格策略"
  244. def __str__(self):
  245. return "%s(%s)%s" % (self.content_object, self.get_valid_period_display(), self.price)

下载数据库使用(务必下载,上面的压缩包数据库是空的!!!)

https://github.com/987334176/luffycity/blob/master/db.sqlite3

修改api应用下的api_urls.py

  1. from django.conf.urls import url
  2. from api import views
  3. urlpatterns = [
  4. url(r'index/$', views.CheckView.as_view()),
  5. ]

a

查看所有学位课并打印学位课名称以及授课老师

修改api应用下的views.py

  1. from django.shortcuts import render,HttpResponse
  2. from api import models
  3. from django.views import View
  4. # Create your views here.
  5. class CheckView(View):
  6. """
  7. 练习题相关
  8. """
  9. def get(self, request):
  10. # a.查看所有学位课并打印学位课名称以及授课老师
  11. degree_list = models.DegreeCourse.objects.all().values('name', 'teachers__name')
  12. print(degree_list)
  13. return HttpResponse('ok')

访问网页:http://127.0.0.1:8000/api/index/

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图1

查看控制台输出:

  1. <QuerySet [{'teachers__name': '李泳谊', 'name': 'Linux自动化运维 · 中级'}, {'teachers__name': 'Alex 金角大王', 'name': 'Python全栈开发 · 中级'}]>

第二种写法:

  1. class CheckView(View):
  2. """
  3. 练习题相关
  4. """
  5. def get(self, request):
  6. # a.查看所有学位课并打印学位课名称以及授课老师
  7. queryset = models.DegreeCourse.objects.all()
  8. for row in queryset:
  9. print(row.name,row.teachers.all())
  10. return HttpResponse('ok')

查看控制台输出:

  1. <QuerySet [{'teachers__name': '李泳谊', 'name': 'Linux自动化运维 · 中级'}, {'teachers__name': 'Alex 金角大王', 'name': 'Python全栈开发 · 中级'}]>

b

查看所有学位课并打印学位课名称以及学位课的奖学金

  1. class CheckView(View):
  2. """
  3. 练习题相关
  4. """
  5. def get(self, request):
  6. # b.查看所有学位课并打印学位课名称以及学位课的奖学金
  7. c_obj=models.DegreeCourse.objects.all()
  8. for i in c_obj:
  9. # 利用degreecourse_price_policy字段进行反向查询
  10. print(i.name,i.degreecourse_price_policy.all().values('price'))
  11. return HttpResponse('ok')

刷新网页,查看控制台输出:

  1. Python全栈开发 · 中级 <QuerySet [{'price': 10.0}]>
  2. Linux自动化运维 · 中级 <QuerySet [{'price': 50.0}]>

第二种写法:

  1. class CheckView(View):
  2. """
  3. 练习题相关
  4. """
  5. def get(self, request):
  6. # b.查看所有学位课并打印学位课名称以及学位课的奖学金
  7. degree_list = models.DegreeCourse.objects.all()
  8. for row in degree_list:
  9. print(row.name)
  10. scholarships = row.scholarship_set.all()
  11. for item in scholarships:
  12. print('------>',item.time_percent,item.value)

执行输出:

  1. Python全栈开发 · 中级
  2. ------> 50 1000
  3. Linux自动化运维 · 中级
  4. ------> 50 1000

c

展示所有的专题课

  1. class CheckView(View):
  2. """
  3. 练习题相关
  4. """
  5. def get(self, request):
  6. # c. 展示所有的专题课
  7. c_obj = models.Course.objects.filter(degree_course__isnull=True)
  8. print(c_obj)
  9. return HttpResponse('ok')

刷新网页,查看控制台输出:

  1. <QuerySet [<Course: Linux基础(付费)>]>

d

查看id=1的学位课对应的所有模块名称

  1. class CheckView(View):
  2. """
  3. 练习题相关
  4. """
  5. def get(self, request):
  6. # d. 查看id=1的学位课对应的所有模块名称
  7. obj = models.DegreeCourse.objects.filter(id=1).values('course__name')
  8. print(obj)
  9. return HttpResponse('ok')

刷新网页,查看控制台输出:

  1. <QuerySet [<Course: Linux基础(付费)>]>

e

获取id = 1的专题课,并打印:课程名、级别(中文)、why_study、what_to_study_brief、所有recommend_courses

  1. class CheckView(View):
  2. """
  3. 练习题相关
  4. """
  5. def get(self, request):
  6. # e. 获取id = 1的专题课,并打印:课程名、级别(中文)、why_study、what_to_study_brief、所有recommend_courses
  7. c_obj = models.Course.objects.filter(id=1)
  8. print(c_obj.values('name'))
  9. print(c_obj.first().get_level_display())
  10. print(c_obj.values('coursedetail__why_study'))
  11. print(c_obj.values('coursedetail__what_to_study_brief'))
  12. print(c_obj.values('coursedetail__recommend_courses'))
  13. return HttpResponse('ok')

刷新网页,查看控制台输出:

  1. <QuerySet [{'name': 'Python开发入门7天特训营'}]>
  2. 初级
  3. <QuerySet [{'coursedetail__why_study': '适合零基础学编程的小白,语言简洁高效,为进入人工智能、数据分析和网站开发做好准备;如果你准备敲下你人生的第一行代码、写出你的第一个程序,路飞学城的入门特训营会是最好的选择'}]>
  4. <QuerySet [{'coursedetail__what_to_study_brief': '1、Python如何才能掌握真正的要领;\r\n2、看完理论课程自己怎么开始动手写出代码;\r\n3、什么才是专业的代码;\r\n4、最流行Python编程工具使用技巧;\r\n5、如何系统且高效的学习Python,遇到问题该如何入手分析\r\n6、可以自主开发各种小程序(如分数打印、猜年龄、用户登录程序、三级菜单等)'}]>
  5. <QuerySet [{'coursedetail__recommend_courses': 1}]>

第二种写法:

  1. Python开发入门7天特训营
  2. 适合零基础学编程的小白,语言简洁高效,为进入人工智能、数据分析和网站开发做好准备;如果你准备敲下你人生的第一行代码、写出你的第一个程序,路飞学城的入门特训营会是最好的选择
  3. 初级
  4. 7
  5. 适合零基础学编程的小白,语言简洁高效,为进入人工智能、数据分析和网站开发做好准备;如果你准备敲下你人生的第一行代码、写出你的第一个程序,路飞学城的入门特训营会是最好的选择
  6. <QuerySet [<Course: Python开发入门7天特训营(付费)>]>

刷新网页,查看控制台输出:

  1. Python开发入门7天特训营
  2. 适合零基础学编程的小白,语言简洁高效,为进入人工智能、数据分析和网站开发做好准备;如果你准备敲下你人生的第一行代码、写出你的第一个程序,路飞学城的入门特训营会是最好的选择
  3. 初级
  4. 7
  5. 适合零基础学编程的小白,语言简洁高效,为进入人工智能、数据分析和网站开发做好准备;如果你准备敲下你人生的第一行代码、写出你的第一个程序,路飞学城的入门特训营会是最好的选择
  6. <QuerySet [<Course: Python开发入门7天特训营(付费)>]>

注意:显示choices的中文,使用get_字段名_display() 就可以了!

f

获取id = 1的专题课,并打印该课程相关的所有常见问题

  1. class CheckView(View):
  2. """
  3. 练习题相关
  4. """
  5. def get(self, request):
  6. # f. 获取id = 1的专题课,并打印该课程相关的所有常见问题
  7. c_obj = models.Course.objects.filter(id=1).first()
  8. # 利用asked_question字段进行反向查询
  9. print(c_obj.asked_question.all().values('question'))
  10. return HttpResponse('ok')

刷新网页,查看控制台输出:

  1. <QuerySet [{'question': '我是零基础,能学会吗?'}, {'question': '需要学习多长时间?'}]>

第二种写法:

  1. class CheckView(View):
  2. """
  3. 练习题相关
  4. """
  5. def get(self, request):
  6. # f. 获取id = 1的专题课,并打印该课程相关的所有常见问题
  7. obj = models.Course.objects.get(id=1)
  8. ask_list = obj.asked_question.all()
  9. for item in ask_list:
  10. print(item.question)
  11. return HttpResponse('ok')

刷新网页,查看控制台输出:

  1. 我是零基础,能学会吗?
  2. 需要学习多长时间?

g

获取id = 1的专题课,并打印该课程相关的课程大纲

  1. class CheckView(View):
  2. """
  3. 练习题相关
  4. """
  5. def get(self, request):
  6. # g.获取id = 1的专题课,并打印该课程相关的课程大纲
  7. c_obj = models.Course.objects.filter(id=1)
  8. print(c_obj.values('coursedetail__courseoutline__title'))
  9. return HttpResponse('ok')

刷新网页,查看控制台输出:

  1. <QuerySet [{'coursedetail__courseoutline__title': 'Python基础知识'}, {'coursedetail__courseoutline__title': 'Python数据类型初识'}]>

第二种写法:

  1. class CheckView(View):
  2. """
  3. 练习题相关
  4. """
  5. def get(self, request):
  6. # g.获取id = 1的专题课,并打印该课程相关的课程大纲
  7. obj = models.Course.objects.get(id=1)
  8. outline_list = obj.coursedetail.courseoutline_set.all()
  9. for item in outline_list:
  10. print(item.title,item.content)
  11. return HttpResponse('ok')

刷新网页,查看控制台输出:

  1. Python基础知识 Python基础知识、开营直播课
  2. Python数据类型初识 Python数据类型初识、流程控制

h

获取id = 1的专题课,并打印该课程相关的所有章节

  1. class CheckView(View):
  2. """
  3. 练习题相关
  4. """
  5. def get(self, request):
  6. # h.获取id = 1的专题课,并打印该课程相关的所有章节
  7. c_obj = models.Course.objects.filter(id=1)
  8. print(c_obj.values('coursechapter__name'))
  9. return HttpResponse('ok')

刷新网页,查看控制台输出:

  1. <QuerySet [{'coursechapter__name': 'Python基础知识'}, {'coursechapter__name': 'Python数据类型初识'}]>

第二种写法,使用反向查询

  1. class CheckView(View):
  2. """
  3. 练习题相关
  4. """
  5. def get(self, request):
  6. # h.获取id = 1的专题课,并打印该课程相关的所有章节
  7. obj = models.Course.objects.get(id=1)
  8. chapter_list = obj.coursechapter_set.all() # 默认obj.表名_set.all()
  9. for item in chapter_list:
  10. print(item.name)
  11. return HttpResponse('ok')

刷新网页,查看控制台输出:

  1. Python基础知识
  2. Python数据类型初识

i

获取id = 1的专题课,并打印该课程相关的所有课时

  1. class CheckView(View):
  2. """
  3. 练习题相关
  4. """
  5. def get(self, request):
  6. # i.获取id = 1的专题课,并打印该课程相关的所有课时
  7. c_obj = models.Course.objects.filter(id=1)
  8. for i in c_obj.values('coursechapter__chapter','coursechapter__name'):
  9. print(i.get('coursechapter__chapter'),i.get('coursechapter__name'))
  10. a_obj=models.CourseChapter.objects.filter(name=i.get('coursechapter__name'))
  11. for j in a_obj.values('coursesection__name'):
  12. print(' ',j.get('coursesection__name'))
  13. return HttpResponse('ok')

刷新网页,查看控制台输出:

  1. 1 Python基础知识
  2. python基础
  3. 2 Python数据类型初识
  4. 数据类型

第二种写法:

  1. class CheckView(View):
  2. """
  3. 练习题相关
  4. """
  5. def get(self, request):
  6. # i.获取id = 1的专题课,并打印该课程相关的所有课时
  7. obj = models.Course.objects.get(id=1)
  8. chapter_list = obj.coursechapter_set.all()
  9. for chapter in chapter_list:
  10. print(chapter.name,chapter.coursesection_set.all())
  11. return HttpResponse('ok')

刷新网页,查看控制台输出:

  1. Python数据类型初识 <QuerySet [<CourseSection: Python开发入门7天特训营(付费):(第2章)Python数据类型初识-数据类型>]>

所有视图都集中在views.py中,扩展不方便。

删除views.py,并创建目录views

在views目录里面创建course.py,它表示和课程相关的视图

注意:视图名最好加上View,这是约定俗成的

  1. from django.shortcuts import render,HttpResponse
  2. from api import models
  3. from rest_framework.views import APIView
  4. class CourseView(APIView):
  5. def get(self,request,*args,**kwargs):
  6. return HttpResponse('ok')

修改api_urls.py

  1. from django.conf.urls import url
  2. from api.views import course
  3. urlpatterns = [
  4. url(r'course/$', course.CourseView.as_view()),
  5. ]

访问网页:http://127.0.0.1:8000/api/course/

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图2

二、DRF版本

在Django rest-framework中提供了5中version设置方式

基于url的get传参方式

比如:/course?version=v1

settings.py,最后一行添加。这里面规定了版本为v1和v2,如果是其他版本,会报404错误!

  1. REST_FRAMEWORK = {
  2. 'DEFAULT_VERSION': 'v1', # 默认版本
  3. 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
  4. 'VERSION_PARAM': 'version' # URL中获取值的key
  5. }

api_urls.py

  1. from django.conf.urls import url
  2. from api.views import course
  3. urlpatterns = [
  4. url(r'course/$', course.CourseView.as_view(),name='test'),
  5. ]

course.py

  1. from django.shortcuts import render,HttpResponse
  2. from api import models
  3. from rest_framework.views import APIView
  4. from rest_framework.versioning import QueryParameterVersioning
  5. from rest_framework.response import Response
  6. class CourseView(APIView):
  7. # 开启版本支持功能
  8. versioning_class = QueryParameterVersioning
  9. def get(self, request, *args, **kwargs):
  10. # 获取版本
  11. print(request.version)
  12. # 获取版本管理的类
  13. print(request.versioning_scheme)
  14. # 反向生成URL
  15. reverse_url = request.versioning_scheme.reverse('test', request=request)
  16. print(reverse_url)
  17. return Response('GET请求,响应内容')

访问网页: http://127.0.0.1:8000/api/course/

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图3

查看Pycharm控制台输出:

  1. v1
  2. <rest_framework.versioning.QueryParameterVersioning object at 0x000001AAE5245F28>
  3. http://127.0.0.1:8000/api/course/?version=v1

基于url的正则方式(推荐)

比如:/v1/users/

settings.py,保持不变

api_urls.py

  1. from django.conf.urls import url
  2. from api.views import course
  3. urlpatterns = [
  4. url(r'^(?P<version>[v1|v2]+)/course/$', course.CourseView.as_view(), name='test'),
  5. ]

course.py,修改versioning_class

  1. from django.shortcuts import render,HttpResponse
  2. from api import models
  3. from rest_framework.views import APIView
  4. from rest_framework.versioning import URLPathVersioning
  5. from rest_framework.response import Response
  6. class CourseView(APIView):
  7. # 开启版本支持功能
  8. versioning_class = URLPathVersioning
  9. def get(self, request, *args, **kwargs):
  10. # 获取版本
  11. print(request.version)
  12. # 获取版本管理的类
  13. print(request.versioning_scheme)
  14. # 反向生成URL
  15. reverse_url = request.versioning_scheme.reverse('test', request=request)
  16. print(reverse_url)
  17. return Response('GET请求,响应内容')

访问网页: http://127.0.0.1:8000/api/v1/course/

注意要带版本,否则报错

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图4

查看Pycharm控制台输出:

  1. v1
  2. <rest_framework.versioning.URLPathVersioning object at 0x00000200F0F2E4A8>
  3. http://127.0.0.1:8000/api/v1/course/

基于 accept 请求头方式

比如:Accept: application/json; version=1.0

老外喜欢用这种方法,因为比较安全

settings.py,保持不变

api_urls.py

  1. from django.conf.urls import url
  2. from api.views import course
  3. urlpatterns = [
  4. url(r'^course/$', course.CourseView.as_view(), name='test'),
  5. ]

course.py,修改versioning_class

  1. from django.shortcuts import render,HttpResponse
  2. from api import models
  3. from rest_framework.views import APIView
  4. from rest_framework.versioning import AcceptHeaderVersioning
  5. from rest_framework.response import Response
  6. class CourseView(APIView):
  7. # 开启版本支持功能
  8. versioning_class = AcceptHeaderVersioning
  9. def get(self, request, *args, **kwargs):
  10. # 获取版本 HTTP_ACCEPT头
  11. print(request.version)
  12. # 获取版本管理的类
  13. print(request.versioning_scheme)
  14. # 反向生成URL
  15. reverse_url = request.versioning_scheme.reverse('test', request=request)
  16. print(reverse_url)
  17. return Response('GET请求,响应内容')

使用postman发送get请求,增加一个头version

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图5

查看Pycharm控制台输出:

  1. v1
  2. <rest_framework.versioning.AcceptHeaderVersioning object at 0x000001AEA89206D8>
  3. http://127.0.0.1:8000/api/course/

基于主机名方式

比如:v1.example.com

settings.py,允许所有主机访问

  1. ALLOWED_HOSTS = ['*']

api_urls.py,保持不变

course.py,修改versioning_class

  1. from django.shortcuts import render,HttpResponse
  2. from api import models
  3. from rest_framework.views import APIView
  4. from rest_framework.versioning import HostNameVersioning
  5. from rest_framework.response import Response
  6. class CourseView(APIView):
  7. # 开启版本支持功能
  8. versioning_class = HostNameVersioning
  9. def get(self, request, *args, **kwargs):
  10. # 获取版本
  11. print(request.version)
  12. # 获取版本管理的类
  13. print(request.versioning_scheme)
  14. # 反向生成URL
  15. reverse_url = request.versioning_scheme.reverse('test', request=request)
  16. print(reverse_url)
  17. return Response('GET请求,响应内容')

修改本机的hosts文件,增加2条记录

  1. 127.0.0.1 v1.example.com
  2. 127.0.0.1 v2.example.com

访问url: http://v1.example.com:8000/api/course/

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图6

查看Pycharm控制台输出:

  1. v1
  2. <rest_framework.versioning.HostNameVersioning object at 0x000001DE71A00470>
  3. http://127.0.0.1:8000/api/course/

访问url: http://v2.example.com:8000/api/course/

查看Pycharm控制台输出:

  1. v2
  2. <rest_framework.versioning.HostNameVersioning object at 0x000001B31D5C3E48>
  3. http://v2.example.com:8000/api/course/

基于django路由系统的namespace

比如:example.com/v1/users/

settings.py,保持不变

api_urls.py

  1. from django.conf.urls import url
  2. from api.views import course
  3. urlpatterns = [
  4. url(r'^v1/', ([url(r'course/', course.CourseView.as_view(), name='test'), ], None, 'v1')),
  5. url(r'^v2/', ([url(r'course/', course.CourseView.as_view(), name='test'), ], None, 'v2')),
  6. ]

course.py

  1. from django.shortcuts import render,HttpResponse
  2. from api import models
  3. from rest_framework.views import APIView
  4. from rest_framework.versioning import NamespaceVersioning
  5. from rest_framework.response import Response
  6. class CourseView(APIView):
  7. # 开启版本支持功能
  8. versioning_class = NamespaceVersioning
  9. def get(self, request, *args, **kwargs):
  10. # 获取版本
  11. print(request.version)
  12. # 获取版本管理的类
  13. print(request.versioning_scheme)
  14. # 反向生成URL
  15. reverse_url = request.versioning_scheme.reverse('test', request=request)
  16. print(reverse_url)
  17. return Response('GET请求,响应内容')

访问url: http://127.0.0.1:8000/api/v1/course/

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图7

查看Pycharm控制台输出:

  1. v1
  2. <rest_framework.versioning.NamespaceVersioning object at 0x0000020BC5FAFDA0>
  3. http://127.0.0.1:8000/api/v1/course/

全局使用方式

settings.py

  1. REST_FRAMEWORK = {
  2. 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
  3. 'DEFAULT_VERSION': 'v1',
  4. 'ALLOWED_VERSIONS': ['v1', 'v2'],
  5. 'VERSION_PARAM': 'version'
  6. }

api_urls.py

  1. from django.conf.urls import url
  2. from api.views import course
  3. urlpatterns = [
  4. url(r'^course/', course.CourseView.as_view(), name='test'),
  5. ]

course.py

  1. from django.shortcuts import render,HttpResponse
  2. from api import models
  3. from rest_framework.views import APIView
  4. # from rest_framework.versioning import NamespaceVersioning
  5. from rest_framework.response import Response
  6. class CourseView(APIView):
  7. # 开启版本支持功能
  8. # versioning_class = NamespaceVersioning
  9. def get(self, request, *args, **kwargs):
  10. # 获取版本
  11. print(request.version)
  12. # 获取版本管理的类
  13. print(request.versioning_scheme)
  14. # # 反向生成URL
  15. # reverse_url = request.versioning_scheme.reverse('test', request=request)
  16. # print(reverse_url)
  17. return Response('GET请求,响应内容')

访问url: http://127.0.0.1:8000/api/course/

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图8

查看Pycharm控制台输出:

  1. v1
  2. <rest_framework.versioning.URLPathVersioning object at 0x000001FF069907F0>

默认版本为v1

源码分析,请参考链接:

http://www.cnblogs.com/derek1184405959/p/8724270.html

总结:在认证,权限,节流之前做了版本处理

API编写

先做专题课

第一版,json

  1. from django.shortcuts import render,HttpResponse
  2. from api import models
  3. from rest_framework.views import APIView
  4. from rest_framework.response import Response
  5. import json
  6. class CourseView(APIView):
  7. def get(self, request, *args, **kwargs):
  8. """
  9. 获取所有专题课信息
  10. :param request:
  11. :param args:
  12. :param kwargs:
  13. :return:
  14. """
  15. # 方式一:
  16. course_list = list(models.Course.objects.all().values('id','name'))
  17. return HttpResponse(json.dumps(course_list,ensure_ascii=False))

访问页面: http://127.0.0.1:8000/api/course/

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图9

第二版,序列化组件

在api应用目录下创建serializers文件夹,在里面创建course.py

  1. from rest_framework import serializers
  2. class CourseSerializer(serializers.Serializer):
  3. id = serializers.IntegerField()
  4. name = serializers.CharField()

修改views目录下的course.py

  1. from django.shortcuts import render,HttpResponse
  2. from api import models
  3. from rest_framework.views import APIView
  4. from rest_framework.response import Response
  5. from api.serializers.course import CourseSerializer
  6. class CourseView(APIView):
  7. def get(self, request, *args, **kwargs):
  8. """
  9. 获取所有专题课信息
  10. :param request:
  11. :param args:
  12. :param kwargs:
  13. :return:
  14. """
  15. # 方式二:
  16. course_list = models.Course.objects.all()
  17. ser = CourseSerializer(instance=course_list,many=True)
  18. return Response(ser.data)

刷新页面,效果如下:

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图10

三、DRF分页

如果当数据量特别大的时候,需要使用分页

REST框架支持自定义分页风格,如果使用的是APIView,你就需要自己调用分页API,确保返回一个分页后的响应。

指定每页大小

修改views目录下course.py

  1. from django.shortcuts import render,HttpResponse
  2. from api import models
  3. from rest_framework.views import APIView
  4. from rest_framework.response import Response
  5. from api.serializers.course import CourseSerializer
  6. from rest_framework.pagination import PageNumberPagination
  7. class CourseView(APIView):
  8. def get(self, request, *args, **kwargs):
  9. # 从数据库中获取数据
  10. queryset = models.Course.objects.all()
  11. # 分页
  12. page = PageNumberPagination()
  13. # paginate_queryset 接收3参数,分别是queryset对象,request,视图
  14. # 这里的self就是CourseView视图
  15. course_list = page.paginate_queryset(queryset,request,self)
  16. # 分页之后的结果执行序列化
  17. ser = CourseSerializer(instance=course_list,many=True)
  18. return Response(ser.data)

修改settings.py,指定每页大小。这里表示每页一条数据

  1. REST_FRAMEWORK = {
  2. 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
  3. 'DEFAULT_VERSION': 'v1',
  4. 'ALLOWED_VERSIONS': ['v1', 'v2'],
  5. 'VERSION_PARAM': 'version',
  6. 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
  7. 'PAGE_SIZE':1
  8. }

访问网页: http://127.0.0.1:8000/api/course/

效果如下:

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图11

获取下一页

怎么获取下一页呢?在url上面加一个参数page=页码数,比如:

http://127.0.0.1:8000/api/course/?page=2

效果如下

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图12

为什么参数是page呢?而不是其他的呢?看下面的源码

  1. class PageNumberPagination(BasePagination):
  2. """
  3. A simple page number based style that supports page numbers as
  4. query parameters. For example:
  5. http://api.example.org/accounts/?page=4
  6. http://api.example.org/accounts/?page=4&page_size=100
  7. """
  8. # The default page size.
  9. # Defaults to `None`, meaning pagination is disabled.
  10. page_size = api_settings.PAGE_SIZE
  11. django_paginator_class = DjangoPaginator
  12. # Client can control the page using this query parameter.
  13. page_query_param = 'page'
  14. page_query_description = _('A page number within the paginated result set.')
  15. # Client can control the page size using this query parameter.
  16. # Default is 'None'. Set to eg 'page_size' to enable usage.
  17. page_size_query_param = None
  18. page_size_query_description = _('Number of results to return per page.')
  19. # Set to an integer to limit the maximum page size the client may request.
  20. # Only relevant if 'page_size_query_param' has also been set.
  21. max_page_size = None
  22. last_page_strings = ('last',)
  23. template = 'rest_framework/pagination/numbers.html'
  24. invalid_page_message = _('Invalid page.')

看这一行

page_query_param = page

它指定了url参数为page

返回code

这里有一个问题,如果连接不上数据,就会报错

所以需要使用异常判断,定义一个字典,返回code

1000表示成功,500表示错误。备注:这个是自己定义的,看你的心情了!

修改views下的course.py

  1. from django.shortcuts import render,HttpResponse
  2. from api import models
  3. from rest_framework.views import APIView
  4. from rest_framework.response import Response
  5. from api.serializers.course import CourseSerializer
  6. from rest_framework.pagination import PageNumberPagination
  7. class CourseView(APIView):
  8. def get(self, request, *args, **kwargs):
  9. response = {'code':1000,'data':None,'error':None}
  10. try:
  11. # 从数据库中获取数据
  12. queryset = models.Course.objects.all()
  13. # 分页
  14. page = PageNumberPagination()
  15. # paginate_queryset 接收3参数,分别是queryset对象,request,视图
  16. # 这里的self就是CourseView视图
  17. course_list = page.paginate_queryset(queryset,request,self)
  18. # 分页之后的结果执行序列化
  19. ser = CourseSerializer(instance=course_list,many=True)
  20. response['data'] = ser.data
  21. except Exception as e:
  22. response['code'] = 500
  23. response['error'] = '获取数据失败'
  24. return Response(response)

访问页面,发现数据多了几个key

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图13

模拟出错

修改views下的course.py,将ORM语句故意改错

  1. from django.shortcuts import render,HttpResponse
  2. from api import models
  3. from rest_framework.views import APIView
  4. from rest_framework.response import Response
  5. from api.serializers.course import CourseSerializer
  6. from rest_framework.pagination import PageNumberPagination
  7. class CourseView(APIView):
  8. def get(self, request, *args, **kwargs):
  9. response = {'code':1000,'data':None,'error':None}
  10. try:
  11. # 从数据库中获取数据
  12. queryset = models.Course.objects.allxx() # 模拟错误
  13. # 分页
  14. page = PageNumberPagination()
  15. # paginate_queryset 接收3参数,分别是queryset对象,request,视图
  16. # 这里的self就是CourseView视图
  17. course_list = page.paginate_queryset(queryset,request,self)
  18. # 分页之后的结果执行序列化
  19. ser = CourseSerializer(instance=course_list,many=True)
  20. response['data'] = ser.data
  21. except Exception as e:
  22. response['code'] = 500
  23. response['error'] = '获取数据失败'
  24. return Response(response)

刷新页面,提示失败

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图14

注意:每一个接口,一定要加try,防止程序崩溃

在公司里面写代码,必须这样。因为线上环境比较复杂,有各自攻击行为存在。所以,必须写异常判断。

而且,需要将异常信息写入日志。方便后续的排错,因为线上的代码,不能直接print,影响业务!

定义code类

这个视图定义了一个字典,用来做初始状态返回。那么其他视图,也需要返回code,再定义一遍?

如果有100个呢?所以,需要为这个功能,单独定义一个类。

这种是通用类,我们一般会放在应用(这里指的是api)下的utils(工具)文件夹中。

在api目录下创建utils文件夹,新建文件response.py

  1. class BaseResponse(object):
  2. def __init__(self):
  3. self.code = 1000
  4. self.data = None
  5. self.error = None
  6. @property # 负责把一个方法变成属性调用
  7. def dict(self):
  8. return self.__dict__

python中的类,都会从object里继承一个dict属性,这个属性中存放着类的属性和方法对应的键值对

修改views下的course.py,导入response

  1. from django.shortcuts import render,HttpResponse
  2. from api import models
  3. from rest_framework.views import APIView
  4. from rest_framework.response import Response
  5. from api.serializers.course import CourseSerializer
  6. from rest_framework.pagination import PageNumberPagination
  7. from api.utils.response import BaseResponse
  8. class CourseView(APIView):
  9. def get(self, request, *args, **kwargs):
  10. # response = {'code':1000,'data':None,'error':None}
  11. ret = BaseResponse()
  12. try:
  13. # 从数据库中获取数据
  14. queryset = models.Course.objects.all()
  15. # 分页
  16. page = PageNumberPagination()
  17. # paginate_queryset 接收3参数,分别是queryset对象,request,视图
  18. # 这里的self就是CourseView视图
  19. course_list = page.paginate_queryset(queryset,request,self)
  20. # 分页之后的结果执行序列化
  21. ser = CourseSerializer(instance=course_list,many=True)
  22. ret.data = ser.data
  23. except Exception as e:
  24. ret.code = 500
  25. ret.error = '获取数据失败'
  26. return Response(ret.__dict__)

刷新页面,效果如下:

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图15

第二版,到这里,就结束了。推荐使用第二种!

四、DRF序列化进阶

ModelSerializer

通常你会想要与Django模型相对应的序列化类。

ModelSerializer类能够让你自动创建一个具有模型中相应字段的Serializer类。

这个**ModelSerializer**类和常规的**Serializer**类一样,不同的是:

  • 它根据模型自动生成一组字段。
  • 它自动生成序列化器的验证器,比如unique_together验证器。
  • 它默认简单实现了.create()方法和.update()方法。

查看serializers目录下course.py,这里我是手动指定了要序列化的字段,比如id和name

但是,还有更方便的方法。使用ModelSerializer,它会自动和ORM表关联。

修改serializers目录下course.py

  1. from rest_framework import serializers
  2. from api import models
  3. class CourseSerializer(serializers.ModelSerializer):
  4. # id = serializers.IntegerField()
  5. # name = serializers.CharField()
  6. class Meta: # 配置项
  7. model = models.Course # Course表
  8. fields = ['id','name'] # 指定序列化的字段

默认情况下,所有的模型的字段都将映射到序列化器上相应的字段。

模型中任何关联字段比如外键都将映射到PrimaryKeyRelatedField字段。默认情况下不包括反向关联,除非像serializer relations文档中规定的那样显示包含。

刷新页面,效果同上!

Model.get_FOO_display

查看官方文档

https://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.get_FOO_display

对于具有选择集的每个字段,该对象将具有一个get_FOO_display()方法,其中FOO是该字段的名称。 此方法返回字段的“可读”值。

查看models.py里面的Course类,看下面这2行

  1. level_choices = ((0, '初级'), (1, '中级'), (2, '高级'))
  2. level = models.SmallIntegerField(choices=level_choices, default=1)

level_choices 它只是一个变量而已,上面2行,可以合并为一行

  1. level = models.SmallIntegerField(choices=((0, '初级'), (1, '中级'), (2, '高级')), default=1)

真正在数据库中,生成字段的是level。choices=xxx,表示它是一个选择集。真正在数据库存储的是1,后面的中文,主要是在前端展示的。这样做的目的,是为了节省磁盘空间。一般数据库用utf-8,一个中文占用3字节。而数字只占用1字节!

那么前端如何显示中文呢?使用get_level_display() ,注意:level是数据库的字段,值的类型必须是choices

修改serializers目录下course.py

  1. from rest_framework import serializers
  2. from api import models
  3. class CourseSerializer(serializers.ModelSerializer):
  4. # 显示choices里面的中文
  5. level_cn = serializers.CharField(source='get_level_display')
  6. class Meta: # 配置项
  7. model = models.Course # Course表
  8. fields = ['id','name','level_cn'] # 指定序列化的字段

注意:level_cn只是一个变量名而已,约定俗成会定义为字段名。这里的get_level_display不需要加括号,它会自动执行!

刷新页面,效果如下:

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图16

一对一

Course和CourseDetail是一对一关系

现在需要显示课时,但是课时在另外一个表(CourseDetail课程详情表)中,可以用双下方法吗?

  1. fields = ['id','name','level_cn','coursedetail__hours']

刷新页面,会报错

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图17

针对一对一的跨表查询,可以使用表名小写.字段名

修改serializers目录下course.py

  1. from rest_framework import serializers
  2. from api import models
  3. class CourseSerializer(serializers.ModelSerializer):
  4. # 显示choices里面的中文
  5. level_cn = serializers.CharField(source='get_level_display')
  6. # 显示课时,对于一对一,使用表名.字段
  7. hours = serializers.CharField(source='coursedetail.hours')
  8. class Meta: # 配置项
  9. model = models.Course # Course表
  10. fields = ['id','name','level_cn','hours'] # 指定序列化的字段

重启django项目,刷新页面

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图18

在Pycharm控制台,会有一个警告信息

  1. UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list:

百度翻译一下:

  1. unOrdEdObjistList警告:分页可能与无序的对象列表产生不一致的结果:

啥意思呢?大概意思就是分页时,没有给它指定排序规则

修改views下的course.py,增加一个order_by就可以了

order_by(‘pk’),表示以主键排序,默认是升序

  1. from django.shortcuts import render,HttpResponse
  2. from api import models
  3. from rest_framework.views import APIView
  4. from rest_framework.response import Response
  5. from api.serializers.course import CourseSerializer
  6. from rest_framework.pagination import PageNumberPagination
  7. from api.utils.response import BaseResponse
  8. class CourseView(APIView):
  9. def get(self, request, *args, **kwargs):
  10. # response = {'code':1000,'data':None,'error':None}
  11. ret = BaseResponse()
  12. try:
  13. # 从数据库中获取数据
  14. queryset = models.Course.objects.all().order_by('pk')
  15. # 分页
  16. page = PageNumberPagination()
  17. # paginate_queryset 接收3参数,分别是queryset对象,request,视图
  18. # 这里的self就是CourseView视图
  19. course_list = page.paginate_queryset(queryset,request,self)
  20. # 分页之后的结果执行序列化
  21. ser = CourseSerializer(instance=course_list,many=True)
  22. ret.data = ser.data
  23. except Exception as e:
  24. ret.code = 500
  25. ret.error = '获取数据失败'
  26. return Response(ret.__dict__)

重启django项目,刷新页面。再次查看Pycharm控制台,就没有警告了!

多对多

CourseDetail表的recommend_courses字段和Course表,是多对多的关系

如果要显示recommend_courses(推荐课程)呢?可以使用表名小写.字段名吗?测试一下

修改serializers目录下course.py

  1. from rest_framework import serializers
  2. from api import models
  3. class CourseSerializer(serializers.ModelSerializer):
  4. # 显示choices里面的中文
  5. level_cn = serializers.CharField(source='get_level_display')
  6. # 显示课时,对于一对一,使用表名.字段
  7. hours = serializers.CharField(source='coursedetail.hours')
  8. recommend_courses = serializers.CharField(source='coursedetail.recommend_courses')
  9. class Meta: # 配置项
  10. model = models.Course # Course表
  11. fields = ['id','name','level_cn','hours','recommend_courses'] # 指定序列化的字段

刷新页面,效果如下:

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图19

发现recommend_courses字段,并不是我们想要的结果

再加一个.all

  1. from rest_framework import serializers
  2. from api import models
  3. class CourseSerializer(serializers.ModelSerializer):
  4. # 显示choices里面的中文
  5. level_cn = serializers.CharField(source='get_level_display')
  6. # 显示课时,对于一对一,使用表名.字段
  7. hours = serializers.CharField(source='coursedetail.hours')
  8. recommend_courses = serializers.CharField(source='coursedetail.recommend_courses.all')
  9. class Meta: # 配置项
  10. model = models.Course # Course表
  11. fields = ['id','name','level_cn','hours','recommend_courses'] # 指定序列化的字段

刷新页面,效果如下:

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图20

发现它是一个queryset对象,如何获取对象里面的属性呢?

get_{field_name}

它是用来获取别的表字段的。

查看serializers目录下course.py,点击CharField。搜索关键字get_{field_name},看源码

  1. def bind(self, field_name, parent):
  2. # In order to enforce a consistent style, we error if a redundant
  3. # 'method_name' argument has been used. For example:
  4. # my_field = serializer.SerializerMethodField(method_name='get_my_field')
  5. default_method_name = 'get_{field_name}'.format(field_name=field_name)
  6. assert self.method_name != default_method_name, (
  7. "It is redundant to specify `%s` on SerializerMethodField '%s' in "
  8. "serializer '%s', because it is the same as the default method name. "
  9. "Remove the `method_name` argument." %
  10. (self.method_name, field_name, parent.__class__.__name__)
  11. )
  12. # The method name should default to `get_{field_name}`.
  13. if self.method_name is None:
  14. self.method_name = default_method_name
  15. super(SerializerMethodField, self).bind(field_name, parent)

修改serializers目录下course.py,专门定义一个方法,用来获取recommend_courses

  1. from rest_framework import serializers
  2. from api import models
  3. class CourseSerializer(serializers.ModelSerializer):
  4. # 显示choices里面的中文
  5. level_cn = serializers.CharField(source='get_level_display')
  6. # 显示课时,对于一对一,使用表名.字段
  7. hours = serializers.CharField(source='coursedetail.hours')
  8. # 显示推荐课程,对于多对多,使用def_字段名
  9. # SerializerMethodField表示序列化字段,使用方法获取
  10. recommend_courses = serializers.SerializerMethodField()
  11. class Meta: # 配置项
  12. model = models.Course # Course表
  13. fields = ['id','name','level_cn','hours','recommend_courses'] # 指定序列化的字段
  14. def get_recommend_courses(self,row):
  15. recommend_list = [] # 空列表
  16. # row表示一行数据, .all()表示取所有关联的书籍
  17. for item in row.coursedetail.recommend_courses.all():
  18. recommend_list.append({'id':item.id,'name':item.name})
  19. return recommend_list

重启2遍django项目,刷新页面,效果如下:

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图21

上面代码中的,列表里面添加字典数据,可以改成列表生成

  1. from rest_framework import serializers
  2. from api import models
  3. class CourseSerializer(serializers.ModelSerializer):
  4. # 显示choices里面的中文
  5. level_cn = serializers.CharField(source='get_level_display')
  6. # 显示课时,对于一对一,使用表名.字段
  7. hours = serializers.CharField(source='coursedetail.hours')
  8. # 显示推荐课程,对于多对多,使用def_字段名
  9. # SerializerMethodField表示序列化字段,使用方法获取
  10. recommend_courses = serializers.SerializerMethodField()
  11. class Meta: # 配置项
  12. model = models.Course # Course表
  13. fields = ['id','name','level_cn','hours','recommend_courses'] # 指定序列化的字段
  14. def get_recommend_courses(self,row):
  15. recommend_list = row.coursedetail.recommend_courses.all()
  16. return [{'id': item.id, 'name': item.name} for item in recommend_list]

重启django项目,刷新页面,效果同上!

看下图中的代码

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图22

这个名字,必须一一对应,否则报错

因为源码里面定义了,它是取get_字段名方法的。

SerializerMethodField 拆分成3个单词:Serializer Method Field。可以理解为序列化,方法,字段

一对多

Course表的degree_course字段和DegreeCourse表示一对多关系

要显示总奖学金

修改serializers目录下course.py

  1. from rest_framework import serializers
  2. from api import models
  3. class CourseSerializer(serializers.ModelSerializer):
  4. # 显示choices里面的中文
  5. level_cn = serializers.CharField(source='get_level_display')
  6. # 显示课时,对于一对一,使用表名.字段
  7. hours = serializers.CharField(source='coursedetail.hours')
  8. # 显示推荐课程,对于多对多,使用def_字段名
  9. # SerializerMethodField表示序列化字段,使用方法获取
  10. recommend_courses = serializers.SerializerMethodField()
  11. # 显示总奖学金,使用表名.字段
  12. total_scholarship = serializers.CharField(source='degree_course.total_scholarship')
  13. class Meta: # 配置项
  14. model = models.Course # Course表
  15. fields = ['id','name','level_cn','hours','recommend_courses','total_scholarship'] # 指定序列化的字段
  16. def get_recommend_courses(self,row):
  17. recommend_list = row.coursedetail.recommend_courses.all()
  18. return [{'id': item.id, 'name': item.name} for item in recommend_list]

刷新页面,效果如下:

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图23

contenttypes反向查询

Course表的price_policy字段和PricePolicy表,是用contenttypes关联的

from rest_framework import serializers
from api import models

class CourseSerializer(serializers.ModelSerializer):
    # 显示choices里面的中文
    level_cn = serializers.CharField(source='get_level_display')
    # 显示课时,对于一对一,使用表名.字段
    hours = serializers.CharField(source='coursedetail.hours')
    # 显示推荐课程,对于多对多,使用def_字段名
    # SerializerMethodField表示序列化字段,使用方法获取
    recommend_courses = serializers.SerializerMethodField()
    # 显示总奖学金,使用表名.字段
    total_scholarship = serializers.CharField(source='degree_course.total_scholarship')
    # 显示价格策略,contenttypes反向查询,使用def_字段名
    price_strategy = serializers.SerializerMethodField()

    class Meta:  # 配置项
        model = models.Course  # Course表
        fields = ['id','name','level_cn','hours','recommend_courses','total_scholarship','price_strategy']  # 指定序列化的字段

    def get_recommend_courses(self,row):
        recommend_list = row.coursedetail.recommend_courses.all()
        return [{'id': item.id, 'name': item.name} for item in recommend_list]

    def get_price_strategy(self,row):
        # .all 表示查询关联的价格策略
        price_list = row.price_policy.all()
        return [{'id': item.id, 'valid_period': item.valid_period,'price': item.price} for item in price_list]

重启django项目,刷新页面,效果如下:

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图24

总结:

序列化类

一对一,使用 表名小写.字段名

一对多,使用 表名小写.字段名

多对多,使用def字段名。注意字段必须先声明为serializers.SerializerMethodField()。字段名和def字段名必须一一对应!

contenttypes反向查询,使用def_字段名。利用contenttypes字段,也是要声明serializers.SerializerMethodField()…

作业

接口

# a.查看所有学位课并打印学位课名称以及授课老师

# b.查看所有学位课并打印学位课名称以及学位课的奖学金

# c.展示所有的专题课

# d. 查看id=1的学位课对应的所有模块名称

# e.获取id = 1的专题课,并打印:课程名、级别(中文)、why_study、what_to_study_brief、所有recommend_courses

# f.获取id = 1的专题课,并打印该课程相关的所有常见问题

# g.获取id = 1的专题课,并打印该课程相关的课程大纲

# h.获取id = 1的专题课,并打印该课程相关的所有章节

将上面几个查询改成接口方式,返回json格式。

注意:每一个查询,都是一个独立的接口

vue.js

通过axios向API发送ajax请求,并显示结果(展示所有的专题课)。

注意:会出现跨域问题。请自行百度!提示:搜索关键字cors

参考答案

接口

修改api_urls.py

from django.conf.urls import url
from api.views import course,degreecourse

urlpatterns = [
    url(r'courses/$',course.CoursesView.as_view()),
    url(r'courses/(?P<pk>\d+)/$',course.CourseDetailView.as_view()),
    url(r'courses/thematic/$',course.CourseThematicView.as_view()),
    url(r'courses/module/(?P<pk>\d+)/$',course.CourseModuleView.as_view()),
    url(r'courses/faq/(?P<pk>\d+)/$',course.CourseFAQView.as_view()),
    url(r'courses/outline/(?P<pk>\d+)/$',course.CourseOutlineView.as_view()),
    url(r'courses/chapter/(?P<pk>\d+)/$',course.CourseChapterView.as_view()),

    url(r'degreecourse/$',degreecourse.DegreeCourseView.as_view()),
    url(r'degreecourse/teachers/$',degreecourse.DegreeCourseTeachersView.as_view()),
    url(r'degreecourse/scholarship/$',degreecourse.DegreeCourseScholarshipView.as_view()),
]

修改serializers目录下的course.py

from rest_framework import serializers
from api import models

class CourseModelSerializer(serializers.ModelSerializer):  # 所有课程
    level_name = serializers.CharField(source='get_level_display')
    hours = serializers.CharField(source='coursedetail.hours')
    course_slogan = serializers.CharField(source='coursedetail.course_slogan')
    recommend_courses = serializers.SerializerMethodField()

    class Meta:
        model = models.Course
        fields = ['id','name','level_name','hours','course_slogan','recommend_courses']

    def get_recommend_courses(self,row):
        recommend_list = row.coursedetail.recommend_courses.all()
        return [ {'id':item.id,'name':item.name} for item in recommend_list]

class CourseThematicModelSerializer(serializers.ModelSerializer):  # 所有的专题课
    level_name = serializers.CharField(source='get_level_display')
    course_type = serializers.CharField(source='get_course_type_display')
    status = serializers.CharField(source='get_status_display')
    degree_course = serializers.CharField(source='degree_course.total_scholarship')

    class Meta:
        model = models.Course
        fields = '__all__'

class CourseModuleModelSerializer(serializers.ModelSerializer):  # 所有的专题课
    degree_course = serializers.CharField(source='degree_course.name')
    class Meta:
        model = models.Course
        fields = ['id','degree_course']

class CourseDetailModelSerializer(serializers.ModelSerializer):  # 具体id的学位课对应的所有模块名称
    level_name = serializers.CharField(source='get_level_display')
    why_study = serializers.CharField(source='coursedetail.why_study')
    what_to_study_brief = serializers.CharField(source='coursedetail.what_to_study_brief')

    recommend_courses = serializers.SerializerMethodField()
    price_strategy = serializers.SerializerMethodField()

    class Meta:
        model = models.Course
        fields = ['id','name','level_name','why_study','what_to_study_brief','recommend_courses','price_strategy']

    def get_recommend_courses(self,row):
        recommend_list = row.coursedetail.recommend_courses.all()
        return [ {'id':item.id,'name':item.name} for item in recommend_list]

    def get_price_strategy(self,row):
        price_list = row.price_policy.all()
        return [{'id': item.id, 'valid_period': item.valid_period,'price': item.price} for item in price_list]

class CourseFAQModelSerializer(serializers.ModelSerializer):  # 具体id专题课程相关的所有常见问题
    asked_question = serializers.SerializerMethodField()

    class Meta:
        model = models.Course
        fields = ['id','name', 'asked_question']

    def get_asked_question(self, row):
        faq_list = row.asked_question.all()
        return [{'id': item.id, 'question': item.question, 'answer': item.answer} for item in faq_list]


class CourseOutlineModelSerializer(serializers.ModelSerializer):  # 具体id课程相关的课程大纲
    asked_question = serializers.SerializerMethodField()

    class Meta:
        model = models.Course
        fields = ['id', 'name', 'asked_question']

    def get_asked_question(self, row):
        outline_list = row.coursedetail.courseoutline_set.all()
        return [{'id': item.id, 'title': item.title, 'content': item.content} for item in outline_list]

class CourseChapterModelSerializer(serializers.ModelSerializer):  # 具体id课程相关的所有章节
    chapter = serializers.SerializerMethodField()

    class Meta:
        model = models.Course
        fields = ['id', 'name', 'chapter']

    def get_chapter(self, row):
        chapter_list = row.coursechapter_set.all()
        return [{'id': item.id, 'name': item.name} for item in chapter_list]

修改serializers目录下的degreecourse.py

from rest_framework import serializers
from api import models

class DegreeCourseModelSerializer(serializers.ModelSerializer):  # 学位课所有信息
    class Meta:
        model = models.DegreeCourse
        fields = '__all__'

class DegreeCourseTeachersModelSerializer(serializers.ModelSerializer):  # 学位课的老师
    teachers = serializers.SerializerMethodField()

    class Meta:
        model = models.DegreeCourse
        fields = ['name','teachers']

    def get_teachers(self,row):
        teachers_list = row.teachers.all()
        return [ {'id':item.id,'name':item.name} for item in teachers_list]

class DegreeCourseScholarshipModelSerializer(serializers.ModelSerializer):  # 学位课的奖学金
    degreecourse_price_policy = serializers.SerializerMethodField()
    class Meta:
        model = models.DegreeCourse
        fields = ['name','degreecourse_price_policy']

    def get_degreecourse_price_policy(self,row):
        scholarships = row.scholarship_set.all()
        return [ {'id':item.id,'time_percent':item.time_percent,'value':item.value} for item in scholarships]

在api目录下utils文件夹,创建文件serialization_general.py

from api.utils.response import BaseResponse
from rest_framework.pagination import PageNumberPagination

class SerializedData(object):  # 序列化通用格式数据
    def __init__(self,request,queryset,serializer_class):
        self.request = request
        self.queryset = queryset
        self.serializer_class = serializer_class


    def get_data(self):
        ret = BaseResponse()
        try:
            # 从数据库获取数据
            queryset = self.queryset.order_by('id')

            # 分页
            page = PageNumberPagination()
            course_list = page.paginate_queryset(queryset, self.request, self)

            # 分页之后的结果执行序列化
            ser = self.serializer_class(instance=course_list, many=True)

            ret.data = ser.data
        except Exception as e:
            print(e)
            ret.code = 500
            ret.error = '获取数据失败'

        return ret.dict

修改views目录下的course.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import URLPathVersioning
from rest_framework.pagination import PageNumberPagination

from api import models
from api.serializers.course import CourseModelSerializer, CourseThematicModelSerializer, CourseModuleModelSerializer, \
    CourseDetailModelSerializer,CourseFAQModelSerializer,CourseOutlineModelSerializer,CourseChapterModelSerializer
from api.utils.response import BaseResponse
from api.utils.serialization_general import SerializedData

class CoursesView(APIView):  # 所有课程,分页展示,每页1个

    def get(self, request, *args, **kwargs):
        # response = {'code':1000,'data':None,'error':None}
        queryset = models.Course.objects.all()
        serializer_class = CourseModelSerializer
        data = SerializedData(request,queryset,serializer_class).get_data()
        return Response(data)


class CourseDetailView(APIView):  # 课程详情
    def get(self, request, pk, *args, **kwargs):
        queryset = models.Course.objects.filter(id=pk)
        serializer_class = CourseDetailModelSerializer
        data = SerializedData(request, queryset, serializer_class).get_data()
        return Response(data)



class CourseThematicView(APIView):  # 所有的专题课
    def get(self, request, *args, **kwargs):
        queryset = models.Course.objects.all()
        serializer_class = CourseThematicModelSerializer
        data = SerializedData(request, queryset, serializer_class).get_data()
        return Response(data)


class CourseModuleView(APIView):  # 具体id的学位课对应的所有模块名称
    def get(self, request, pk, *args, **kwargs):
        queryset = models.Course.objects.filter(degree_course_id=pk)
        serializer_class = CourseModuleModelSerializer
        data = SerializedData(request, queryset, serializer_class).get_data()
        return Response(data)


class CourseFAQView(APIView):  # 具体id的课程相关的所有常见问题
    def get(self, request, pk, *args, **kwargs):
        queryset = models.Course.objects.filter(id=pk)
        serializer_class = CourseFAQModelSerializer
        data = SerializedData(request, queryset, serializer_class).get_data()
        return Response(data)


class CourseOutlineView(APIView):  # 具体id课程相关的课程大纲
    def get(self, request, pk, *args, **kwargs):
        queryset = models.Course.objects.filter(id=pk)
        serializer_class = CourseOutlineModelSerializer
        data = SerializedData(request, queryset, serializer_class).get_data()
        return Response(data)


class CourseChapterView(APIView):  # 具体id课程相关的所有章节
    def get(self, request, pk, *args, **kwargs):
        queryset = models.Course.objects.filter(id=pk)
        serializer_class = CourseChapterModelSerializer
        data = SerializedData(request, queryset, serializer_class).get_data()
        return Response(data)

在views目录下创建文件degreecourse.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import URLPathVersioning
from rest_framework.pagination import PageNumberPagination

from api import models
from api.serializers.degreecourse import DegreeCourseModelSerializer,DegreeCourseTeachersModelSerializer
from api.serializers.degreecourse import DegreeCourseScholarshipModelSerializer
from api.utils.response import BaseResponse

class DegreeCourseView(APIView):  # 所有学位课

    def get(self,request,*args,**kwargs):
        # response = {'code':1000,'data':None,'error':None}
        ret = BaseResponse()
        try:
            # 从数据库获取数据
            queryset = models.DegreeCourse.objects.all()

            # 分页
            page = PageNumberPagination()
            course_list = page.paginate_queryset(queryset,request,self)

            # 分页之后的结果执行序列化
            ser = DegreeCourseModelSerializer(instance=course_list,many=True)

            ret.data = ser.data
        except Exception as e:
            ret.code = 500
            ret.error = '获取数据失败'

        return Response(ret.dict)


class DegreeCourseTeachersView(APIView):  # 学位课对应的老师
    def get(self, request, *args, **kwargs):
        ret = BaseResponse()
        try:
            # 从数据库获取数据
            # 防止出现UnorderedObjectListWarning: Pagination may yield...
            queryset = models.DegreeCourse.objects.get_queryset().order_by('id')
            print(queryset)
            # 分页
            page = PageNumberPagination()
            course_list = page.paginate_queryset(queryset, request, self)

            # 分页之后的结果执行序列化
            ser = DegreeCourseTeachersModelSerializer(instance=course_list, many=True)
            print(ser.data)

            ret.data = ser.data
        except Exception as e:

            print(e)

            ret.code = 500
            ret.error = '获取数据失败'

        return Response(ret.dict)

class DegreeCourseScholarshipView(APIView):  # 学位课对应的老师
    def get(self, request, *args, **kwargs):
        ret = BaseResponse()
        try:
            # 从数据库获取数据
            # 防止出现UnorderedObjectListWarning: Pagination may yield...
            queryset = models.DegreeCourse.objects.get_queryset().order_by('id')
            print(queryset)
            # 分页
            page = PageNumberPagination()
            course_list = page.paginate_queryset(queryset, request, self)

            # 分页之后的结果执行序列化
            ser = DegreeCourseScholarshipModelSerializer(instance=course_list, many=True)
            print(ser.data)

            ret.data = ser.data
        except Exception as e:

            print(e)

            ret.code = 500
            ret.error = '获取数据失败'

        return Response(ret.dict)

访问以下url:

查看所有学位课并打印学位课名称以及授课老师

http://127.0.0.1:8000/api/v1/degreecourse/teachers/

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图25

查看所有学位课并打印学位课名称以及学位课的奖学金

http://127.0.0.1:8000/api/v1/degreecourse/scholarship/

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图26

展示所有的专题课

http://127.0.0.1:8000/api/v1/courses/thematic/

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图27

查看id=1的学位课对应的所有模块名称

http://127.0.0.1:8000/api/v1/courses/module/1/

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图28

获取id = 1的专题课,并打印:课程名、级别(中文)、why_study、what_to_study_brief、所有recommend_courses

http://127.0.0.1:8000/api/v1/courses/1/

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图29

获取id = 1的专题课,并打印该课程相关的所有常见问题

http://127.0.0.1:8000/api/v1/courses/faq/1/

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图30

coursedetail获取id = 1的专题课,并打印该课程相关的课程大纲

http://127.0.0.1:8000/api/v1/courses/outline/1/

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图31

获取id = 1的专题课,并打印该课程相关的所有章节

http://127.0.0.1:8000/api/v1/courses/chapter/1/

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图32

vue.js

在cmd中进入一个空目录,输入下面的命令,创建一个项目mysite

vue init webpack mysite

执行之后有很多选项,详情请参考:

https://www.cnblogs.com/xiao987334176/p/9372479.html#autoid-5-1-0

执行2个命令,启动vue项目

cd mysite
npm run dev

访问vue的网页:http://localhost:8080

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图33

进入vue项目,里面有一个index.html,它是最大的母版。

里面定义了一个div,id为app

进入src目录,修改App.vue。删除图片和css样式

<template>
  <div id="app">

    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>

</style>

进入src—>components,修改HelloWorld.vue,删除多余的a标签

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: '欢迎使用路飞学城'
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

关闭vue项目,安装axios

npm install axios --save

重新启动vue项目

npm run dev

修改main.js,导入axios,并定义一个全局变量$axios

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import axios from 'axios'  //导入axios

Vue.prototype.$axios = axios  //声明全局变量
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

进入src—>components,修改HelloWorld.vue。让页面加载完成后,使用axios发送请求

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: '欢迎使用路飞学城'
    }
  },
  mounted(){  //页面加载完成后
    this.initCourse();  //执行此方法
  },
  methods:{
    initCourse:function () {
      //向后台发送ajax请求
      this.$axios.request({
        url:'http://127.0.0.1:8000/api/v1/courses/',
        method:'GET',
        responseType:'json',
      }).then(function (arg) {
        //成功之后
        console.log(arg);
      }).catch(function (err) {
        //发生错误
        console.log(err);
      })
    }
  },
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

刷新网页,查看Console,提示不允许访问

Day99 作业讲解,DRF版本,DRF分页,DRF序列化进阶 - 图34

只要看到了Access-Control-Allow-Origin,就表示出现跨域

关于跨域问题,如何解决。请访问下一篇文章:

https://www.cnblogs.com/xiao987334176/articles/9457580.html