路飞学城项目

路飞学城项目学位课表 老师表和价格策略表 fromdjango dbimportmode contrib contenttypes fieldsimport GenericRelat contrib contenttypes modelsimport

学位课表、老师表和价格策略表

from django.db import models from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.contrib.contenttypes.models import ContentType class DegreeCourse(models.Model): """学位课程""" name = models.CharField(max_length=128, unique=True) course_img = models.CharField(max_length=255, verbose_name="缩略图") brief = models.TextField(verbose_name="学位课程简介", ) total_scholarship = models.PositiveIntegerField(verbose_name="总奖学金(贝里)", default=40000) mentor_compensation_bonus = models.PositiveIntegerField(verbose_name="本课程的导师辅导费用(贝里)", default=15000) period = models.PositiveIntegerField(verbose_name="建议学习周期(days)", default=150, help_text='为了计算学位奖学金') prerequisite = models.TextField(verbose_name="课程先修要求", max_length=1024) teachers = models.ManyToManyField("Teacher", verbose_name="课程讲师") # 用于GenericForeignKey反向查询,不会生成表字段,切勿删除 degreecourse_price_policy = GenericRelation("PricePolicy") class Teacher(models.Model): """讲师、导师表""" name = models.CharField(max_length=32, verbose_name='姓名') role_choices = ((1, '讲师'), (2, '导师')) role = models.SmallIntegerField(choices=role_choices, default=1) title = models.CharField(max_length=64, verbose_name="职位、职称") signature = models.CharField(max_length=255, verbose_name="导师签名", blank=True, null=True) image = models.CharField(max_length=128, verbose_name='头像') brief = models.TextField(max_length=1024, verbose_name='简介') class PricePolicy(models.Model): """价格与有课程效期表""" content_type = models.ForeignKey(ContentType, verbose_name='关联普通课或者学位课表',related_name='x1') object_id = models.PositiveIntegerField(verbose_name='关联普通课或者学位课中的课程ID') content_object = GenericForeignKey('content_type', 'object_id') valid_period_choices = ( (1, '1天'), (3, '3天'), (7, '1周'), (14, '2周'), (30, '1个月'), (60, '2个月'), (90, '3个月'), (180, '6个月'), (210, '12个月'), (540, '18个月'), (720, '24个月'), ) valid_period = models.SmallIntegerField(choices=valid_period_choices, verbose_name='课程周期') price = models.FloatField(verbose_name='价格')

我们先通过这三张表来实现一些简单的查询api

查询课程列表

在rest_framework中我们的视图类何以继承多种类,我们可以不同的需求进行选择

我们现在的需求是查询课程列表,首先我们需要定义url,这里我们的url使用 api/xxx/的形式,需要做一次分发,所以在项目的url中

from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^api/', include('api.urls')), ]

然后在我们的app中定义分发的url

from django.conf.urls import url from .views import course from .views import price urlpatterns = [ url(r'^course/$', course.CourseView.as_view({'get':'list'})), url(r'^course/(?P 
    
      \d+)$', course.CourseView.as_view({'get':'retrieve'})), url(r'^price/$', price.PriceView.as_view()), ] 
    

原本我们的视图都是写在app的views.py文件中,但是由于可能涉及的逻辑较多,我们可以将视图分开,不同的表对应不同的视图文件

路飞学城项目

视图内容

from rest_framework.views import APIView from rest_framework.viewsets import GenericViewSet from rest_framework.response import Response from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer from django.core.exceptions import ObjectDoesNotExist from api import models from api.response.base import BaseResponse from api.serializers.course import CourseSerializer,CourseDetailSerializer from api.pagination.page import LuffyPageNumberPagination class MyException(Exception): def __init__(self,msg): self.msg = msg class CourseView(GenericViewSet): def list(self,request,*args,kwargs): """ 获取课程列表 :return: """ # queryset = [{id:,,name:...},{id:,,name:...},] # 方式一: # select id,name from course # course_list = queryset类型[{id:,,name:...},{id:,,name:...},] # course_list = models.DegreeCourse.objects.all().values('id','name') # course_list = list(course_list) # val = json.dumps(course_list,ensure_ascii=False) # return HttpResponse(val) # 方式二: # course_list = models.DegreeCourse.objects.all().values('id','name') # course_list = list(course_list) # return JsonResponse(course_list,safe=False,json_dumps_params={'ensure_ascii':False}) # 方法三: # select id,name from course # course_list=Queryset=[obj,obj,obj,obj, obj,obj,obj,obj,obj,obj, ] # course_list = models.DegreeCourse.objects.all().defer('name') """ ret = {'code':1000,'data':None,'error':None} try: # QuerySet,是django的类型 # 1. 获取数据 course_list = models.DegreeCourse.objects.all().only('id','name').order_by('-id') # 2. 对数据进行分页 page = LuffyPageNumberPagination() page_course_list = page.paginate_queryset(course_list,request,self) # 3. 对数据序列化 ser = CourseSerializer(instance=page_course_list,many=True) ret['data'] = ser.data except Exception as e: ret['code'] = 1001 ret['error'] = '获取数据失败' return Response(ret) """ ret = BaseResponse() try: # QuerySet,是django的类型 # 1. 获取数据 course_list = models.DegreeCourse.objects.all().only('id', 'name').order_by('-id') # 2. 对数据进行分页 page = LuffyPageNumberPagination() page_course_list = page.paginate_queryset(course_list, request, self) # 3. 对数据序列化 ser = CourseSerializer(instance=page_course_list, many=True) ret.data = ser.data except Exception as e: ret.code = 1001 ret.error = '获取数据失败' return Response(ret.dict)

由于我们查询的是课程列表,所以应该对应的是list函数

而在查询的过程中我们用到了3种方式,前两种方式我们没有用到serializers序列化

方式1

# queryset = [{id:,,name:...},{id:,,name:...},] # 方式一: # select id,name from course # course_list = queryset类型[{id:,,name:...},{id:,,name:...},] course_list = models.DegreeCourse.objects.all().values('id','name') course_list = list(course_list) val = json.dumps(course_list,ensure_ascii=False) return HttpResponse(val)

这里我们用values方法从数据库中拿到[{id:,,name:…},{id:,,name:…},]形式的queryset数据,然后直接用json进行序列化,这里要注意,由于我们name中包含中文,在序列化时会将中文转化为ascii的编码,加上参数ensure_ascii=False就可以让它正常显示中文了

方式2

course_list = models.DegreeCourse.objects.all().values('id','name') course_list = list(course_list) return JsonResponse(course_list,safe=False,json_dumps_params={'ensure_ascii':False})

我们使用django的JsonResponse进行序列化并返回数据,但是由于JsonResponse有一个特点,如果传的不是字典会报错,所以需要加safe=False参数防止它报错,同样为了正常显示中文,我们还需要加上方式1中的参数json_dumps_params={‘ensure_ascii’:False}

 

 方式3

ret = {'code':1000,'data':None,'error':None} try: # QuerySet,是django的类型 # 1. 获取数据 course_list = models.DegreeCourse.objects.all().only('id','name').order_by('-id') # 2. 对数据进行分页 page = LuffyPageNumberPagination() page_course_list = page.paginate_queryset(course_list,request,self) # 3. 对数据序列化 ser = CourseSerializer(instance=page_course_list,many=True) ret['data'] = ser.data except Exception as e: ret['code'] = 1001 ret['error'] = '获取数据失败' return Response(ret)

这里我们使用serializers进行序列化,首先要查询到包含数据对象的queryset,在查询时我们用到了only参数,这个参数的意思是查询到的对象中只包含我们only中的字段,如果我们依然用对象.其它字段,那么会再进行一次数据库查询,与only对应的是defer,它的意思

是查询到的对象中不包含某些字段,查询到数据后我们对数据进行分页并序列化

分页组件

from rest_framework.pagination import PageNumberPagination class LuffyPageNumberPagination(PageNumberPagination): page_size = 1 max_page_size = 20 page_size_query_param = 'size'

序列化组件

from rest_framework import serializers from rest_framework.serializers import Serializer,ModelSerializer from api import models class CourseSerializer(ModelSerializer): class Meta: model = models.DegreeCourse fields = ['id','name']

这些组件我们都写在单独的文件中,使用时导入使用

路飞学城项目

在之前的使用中,我们通过序列化类实例出对象ser后,都是直接将ser.data返回,这样的方式不是很好,我们需要返回更多的信息,所以在这里我们定义了ret = {‘code’:1000,’data’:None,’error’:None},用于返回更多的信息,当数据取成功后我们将数据放到ret[“data”]中

同时取数据时我们还在用try捕捉异常,如果取数据时出错,则将错误信息放到ret[“error”]中,最后返回ret

我们也可以将上面ret这个字典的内容封装到一个类中使用

class BaseResponse(object): def __init__(self,code=1000,data=None,error=None): self.code = code self.data = data self.error = error @property def dict(self): return self.__dict__

在视图中,可以直接使用这个类实例化一个对象进行使用

ret = BaseResponse() try: # QuerySet,是django的类型 # 1. 获取数据 course_list = models.DegreeCourse.objects.all().only('id', 'name').order_by('-id') # 2. 对数据进行分页 page = LuffyPageNumberPagination() page_course_list = page.paginate_queryset(course_list, request, self) # 3. 对数据序列化 ser = CourseSerializer(instance=page_course_list, many=True) ret.data = ser.data except Exception as e: ret.code = 1001 ret.error = '获取数据失败' return Response(ret.dict)

获取课程详细

拿到课程列表后我们就应该能通过点击获取每个课程的详细信息了,首先还是定义url

from django.conf.urls import url from .views import course from .views import price urlpatterns = [ url(r'^course/$', course.CourseView.as_view({'get':'list'})), url(r'^course/(?P 
    
      \d+)$', course.CourseView.as_view({'get':'retrieve'})), url(r'^price/$', price.PriceView.as_view()), ] 
    

这里我们和课程列表使用了同样的视图类,由于都是get请求所以我们要在as_view中增加参数来进行区分

课程详细的serializers类

""" class CourseDetailSerializer(ModelSerializer): class Meta: model = models.DegreeCourse fields = '__all__' depth = 1 """ class CourseDetailSerializer(ModelSerializer): show_teachers = serializers.SerializerMethodField() price_policy = serializers.SerializerMethodField() class Meta: model = models.DegreeCourse fields = ['id','name','show_teachers','price_policy'] def get_show_teachers(self,obj): teacher_list = obj.teachers.all() return [{'id':row.id,'name':row.name} for row in teacher_list] def get_price_policy(self,obj): price_policy_list = obj.degreecourse_price_policy.all() return [{'id': row.id, 'price': row.price,'period':row.get_valid_period_display()} for row in price_policy_list]

由于课程和老师还有价格策略表有关联,默认情况下对于老师表这种多对多的字段会展示对应老师的id列表,这里我们使用depth参数,当为1时,与课程关联的老师的信息也会详细显示,如果老师也有关联的字段,那么可以设置depth=2来展示

当然,我们这里也可以通过serializers.SerializerMethodField()添加两个自定义的字段,再通过get_字段名的方式获取了与课程相关的老师的信息和价格策略信息,这里返回的都是列表中加字典的数据形式

在视图类中我们定义retrieve方法

def retrieve(self,request,pk,*args,kwargs): """ 示例1: ret = BaseResponse() try: obj = models.DegreeCourse.objects.filter(id=pk).first() if not obj: raise MyException('数据不存在') except MyException as e: ret.code = 1001 ret.error = e.msg except Exception as e: ret.code = 1002 ret.error = str(e) return Response(ret.dict) """ # 示例2: ret = BaseResponse() try: obj = models.DegreeCourse.objects.get(id=pk) # obj = CourseDetailSerializer.__new__ # obj.__init__ # many=False, # obj= CourseDetailSerializer的对象来进行序列化数据。 # obj.__init__ # many=True # obj = ListSerializer() 的对象来进行序列化数据。 # obj.__init__ ser = CourseDetailSerializer(instance=obj, many=False) ret.data = ser.data except ObjectDoesNotExist as e: ret.code = 1001 ret.error = '查询数据不存在' except Exception as e: ret.code = 1002 ret.error = "查询失败" return Response(ret.dict)

在这个方法中我们获取pk值对应的课程数据对象,在通过序列化类进行序列化,这里需要注意的是序列化单个对象时,参数many=False,其实many参数决定了我们用来序列化的类,True和False对应的__new__方法中生成的对象是不同的,序列化完成后同样是使用

ret来返回数据信息,这里我们同样进行异常捕获,只是示例1中我们自己定义了一个错误类

class MyException(Exception): def __init__(self,msg): self.msg = msg

用户认证

在做用户认证时,我们还是先创建一个认证类

from rest_framework.authentication import BaseAuthentication from rest_framework.request import Request from rest_framework.exceptions import AuthenticationFailed class LuffyAuthentication(BaseAuthentication): def authenticate(self,request): # 去请求体中获取POST值: request.data -> request._request.POST # 去URL中获取GET传值:request.query_params -> request._request.GET # token = request.query_params.get('token') # 去数据库中检查 # 认证失败,抛出异常 # raise AuthenticationFailed('认证失败') # if not token: # raise AuthenticationFailed({'code':9999,'error':'认证失败'}) # # 认证成功,(request.user,request.auth) # return ('alex',None) pass

这里要注意的是由于rest_freamwork对request又进行了一次封装,所以我没呢可以从request.data中取到请求体中的数据,也可以从request.query_params中取到url中GET的传值

认证是我们可以先从request.query_params中取到token的值,再根据token判断是否登录,如果验证成功了那么我们可以返回一个元组,元组的值会分别赋给request.user和request.auth,验证失败了则可以抛出异常AuthenticationFailed,在之前我们都只是抛出

异常的信息,在返回时会自动给我们返回一个字典{“detail”:异常信息},但是现在我们需要返回更多的信息,所以我们可以在异性信息中放入一个字典AuthenticationFailed({‘code’:9999,’error’:’认证失败’})

如果我们不返回元组,也不抛出异常,而是返回None,那么默认会是一个匿名用户,在request.user中会取到Anonymous,我们也可以在settings中配相关参数,来决定返回None时request.user和request.auth的值

REST_FRAMEWORK = { 'UNAUTHENTICATED_USER':None, 'UNAUTHENTICATED_TOKEN':None # 'UNAUTHENTICATED_USER': lambda : "匿名用户", # 'UNAUTHENTICATED_TOKEN': lambda : '匿名Token', }

可以是None,也可以是我们自己定义的匿名用户

 

转载于:https://www.cnblogs.com/weiwu1578/articles/8876956.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/205202.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午6:33
下一篇 2026年3月19日 下午6:34


相关推荐

  • java中的quartz_java 中对Quartz表达式的执行

    java中的quartz_java 中对Quartz表达式的执行执行函数 publicclassH staticList gt list null NewsBaseDaon null SuporbuyBase null ExhibationBa null Overridepubl

    2026年2月6日
    2
  • nginx做正向代理_反向代理和正向代理

    nginx做正向代理_反向代理和正向代理Nginx正向代理四种方式为什么需要正向代理案例配置方式第一种生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML图表FLowchart流程图导出与导入导出导入为什么需要正向代理如果我们的服务部署在公司内网环境,不能直接访问互联网服务,就需要通过可以访问互联网的代理服务器来实现访问互联网的服务。此处我们使用Nginx作为代理服务器。案例互联网上的接口:https://

    2022年8月30日
    6
  • 推荐7个冷门手机APP,每一个都让我相见恨晚

    推荐7个冷门手机APP,每一个都让我相见恨晚推荐 7 个让我相见恨晚的手机 APP1 SmartKit360S 是一个全能的工具箱软件 只有 10M 的大小 却提供了 40 多个实用工具 有了它 就不需要下载这么多软件了 SmartKit360 的工具类别非常丰富 比如常用工具 新闻 社交 购物等等 它相比一个木函更加接地气一点 两者搭配起来使用更爽 并且支持在桌面上创建并添加快捷方式 让你手机秒变生产力工具百宝箱 2 智办事智办事是一款以目标为导向 以人为中心 以成果为标准的目标管理软件 将世界 500 强的工

    2025年9月29日
    4
  • 新手上路之oracle 视图 索引(了解)笔记

    新手上路之oracle 视图 索引(了解)笔记一.视图视图:建立在表|结果集|视图上的虚拟表,有以下作用1、简化:select查询语句2、重用:封装select语句命名3、隐藏:内部细节4、区分:相同数据不同查询不是所有的用户都有创建视图的权限1、前提:createview–>组connectresourcedba2、授权:–>sqlplus/nologa)、sys登录connsys

    2022年7月22日
    10
  • Oracle 错误总结及问题解决 ORA「建议收藏」

    Oracle 错误总结及问题解决 ORA「建议收藏」ORA错误大全

    2022年5月31日
    27
  • Java——JDBC连接数据库(步骤详解!!!)

    Java——JDBC连接数据库(步骤详解!!!)JDBC的全称是:JavaDatabaseConnectivity,即Java数据库连接。JDBC可以通过载入不同的数据库的“驱动程序”而与不同的数据库进行连接。那么,在数据库连接的时候,我使用的是MySQL,Java集成开发环境是Eclipse。要使用JDBC来访问MySQL数据库,首先需要添加MySQL数据库驱动程序。下面,我来为大家讲解一下这其中的步骤(听着名字很高大上,但仔细看步骤会觉得其实没那么难!!!)????????????Step1:www.mysql.co

    2022年7月26日
    16

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号