正文共: 8510字 4图

预计阅读时间: 22分钟

本文干货满满,篇幅较长,可以跳过已经掌握的内容进行阅读。


重点内容回顾-DRF_数据

每日分享

Overthinking ruins you. Ruins the situation, twists it around, makes you worry and just makes everything much worse than it actually is.

过度的思考会毁了你。使你现在的处境糟糕,让你曲解其中的意思,让你担忧,让每一件事都变的更加的糟糕。

小闫语录:

事情不要看太透,做人不要太精明。不知道你有没有听说过一个词『大智若愚』,它是一种大智慧,有德有智,看透万物,但是不去计较那么多。将格局放大,将眼光放远,你会发现不一样的世界。也许你会为了一件小事耿耿于怀,也许你会因为一件琐事久久不能释怀,甚至影响了你正常的生活。并不是说你错,在这件事上你占理,这件事你想的没错,只是它不值得你去花费如此多的精力罢了。将所有的精力放在你主要的事情上,对于一些琐事、一些惹恼的小人,一些阻碍你前进的事物,不妨看淡一点,暂时的妥协并不是向他们低头,而是跟本没把他们放在心上。事情不要想的的太透,太过的执拗会让你走向错误的方向,点到即止,一句话也许只是表面意思,并没有那么多深层意思。做人不要太精明,看透不说透,不要将自己过的那么累,也不要给别人难堪。


重点内容回顾-DRF_序列化_02


重点内容回顾-DRF

1. ​on_delete

on_delete​是定义模型类中外键的一个选项。​on_delete​选项指明的是主表删除数据的时候,对于外键引用的表数据如何处理。

在django.db.models中包含了可选的常量,常用的有三种:

a.​CASCADE级联​,删除主表数据的时候,连同删除外键表中的数据。这个就有点狠了,按需求慎用。

b.​PROTECT保护​,通过抛出一个异常ProtectedError异常,来阻止删除主表中被外键引用的数据。

c.​SET_NULL​设置为 ​NULL​,代表的是主表删除数据的时候,将外键关联的表数据设置为NULL。仅仅在该字段null=True,允许为null时可用。

2. ​related_name

related_name​是在定义模型类时,外键的一个选项。它的功能下面慢慢给大家分析一下。

之前我们在数据库查询操作中,由一查多的时候,是下面的操作:

# 1.查询id为200001的地区area = Area.objects.get(id=200001)# 2.查询area的下级地区# 由一查多:一对象.多类名小写__set.all()sub_areas = area.area_set.all()

一旦设置了 ​related_name='subs'​的时候,我们查询area的下级地区的时候,就可以改为下面的操作:

sub_areas = area.subs.all()

相当于是将 ​多类名小写_set​改为了related_name设置的 ​subs​。是不是很方便呢?

ForeignKey('self')​代表的是自关联

3.一些常用的命令

a. 创建Django工程:

django-admin startproject 工程名称

b. 创建子应用:

python manage.py startapp 子应用名称

c. 使用shell:

python manage.py shell

d. 打开celery执行者:(一定要在celery的目录上一级打开打开终端执行命令)

celery -A celery目录.main worker -l 日志级别celery -A celery_task.main worker -l info

e. 我们设置了前端开发服务器,所以每次使用的时候一定要记得打开:(在静态文件目录下执行下面的命令)

live-server

f. 迁移

生成迁移文件:

python manage.py makemigrations

同步到数据库中:

python manage.py migrate

g. MySQL数据库中修改表中数据:

update 表名 set 字段名=要改的值 [where 查询指定数据的条件]update tb_users set email_active=0 where id=2;

h. shell脚本添加地区数据:(是直接远程连接导入数据)

mysql -u<用户名> -p<密码> -h<数据库服务器> <数据库名> < sql文件;mysql -umeiduo -pmeiduo -h172.16.179.139 meiduo_mall < areas.sql;

要想上面的命令将来可以被多次执行,可以将上面的命令写入一个 ​.sh​文件中,在文件的首行必须指定一行命令:

#! /bin/bash

也许每个人电脑中bash的位置不同,根据自己电脑写即可,mac和Ubuntu中是不同的。

最后还要想执行该shell文件,必须修改文件的可执行权限:(这条命令作为帮助大家回忆Linux命令)

chmod a+x import_areas_data_to_db.sh

上面的chmod不需要解释,a代表的是all(即全部三者:u(user该文件的所有者)、g(group该文件所有者所在的用户组)、o(other表示其他用户)),x代表的是执行权限。上面的命令的意思就是『此文件给所有的用户添加执行权限』


+代表的是增加权限、-代表的是撤销权限、=代表的是设定权限

r代表可读权限,就是可以通过 ​ls​命令查看这个目录的内容。w代表的是写入权限,就是可以通过 ​touch​等命令在该目录下创建新文件。x代表的是执行权限,就是可以通过 ​cd​命令进入这个目录等。

4.关联对象的嵌套序列化

4.1PrimaryKeyRelatedField

将关联对象序列化为关联对象的主键。

subs = PrimaryKeyRelatedField(label='下级地区',read_only=True)或者:subs = PrimaryKeyRelatedField(label='下级地区',queryset=Area.objects.all())


包含read_only=True参数的时候,该字段仅仅用在序列化。

包含queryset参数的时候,将被用在反序列化时参数校验。


4.2使用关联对象的序列化器类

采用指定的序列化器将关联对象进行序列化

subs = AreaSerializer(label='下级地区',many=True)

4.3StringRelatedField

将关联对象序列化为关联对象的字符串表示方式,(即关联对象模型类_str_方法的返回值)

subs = serializers.StringRelatedField(label='下级地区')

说明

我们在昨天的文章『​​我是一个链接​​』中查询指定地区的时候,接口设计中响应数据如下:

{    "id":"地区id",    "name":"地区名称",    "subs":[        {            "id":"下级地区",            "name":"下级地区名称"        }    ]}

根据上面可知,我们只需要将数据序列化为id和name,那么我们使用指定的序列化器类序列化即可。

5.DRF框架

5.1web开发两种模式

前后端不分离​:前端看到的效果是由后端进行控制,由后端进行模板渲染,给客户端返回渲染之后完整的页面内容。

前后端分离​:后端只返回前端所需的数据,至于数据怎么显示,由前端自己控制。

5.2Restful API接口设计风格

关键点​:

a.url地址尽量使用名词,不要使用动词;

b.请求url地址采用不同的请求方式执行不同的操作;(POST新增/GET获取/PUT修改/DELETE删除)

c.过滤参数可以放在查询字符串中;

d.响应数据返回&响应状态码;(200获取或修改成功/201新增成功/204删除成功/404资源不存在/400客户端请求有误/500服务器错误)

e.响应数据格式JSON。

5.3序列化&反序列化

下面从我们最近推文的项目来简单的理解两个概念。

序列化​:将模型对象转换为字典或者json数据的过程。

反序列化​:将前端传递的数据保存到模型对象中的过程。

5.4序列化器Serializer

5.4.1功能

进行数据的序列化和反序列化。

5.4.2序列化器定义

继承自 ​serializers.Serializer​(​重点掌握​),里面的字段需要自己定义。

class 序列化器类名(serializers.Serializer):    # 字段名 = serializer.字段类型(选项参数)

如果我们想要使用序列化器对应的是Django的模型类,那么可以继承自 ​serializers.ModelSerializer​,它会依据模型类的字段自动生成序列化器类的字段,而且已经实现了create和update的代码。

在使用ModelSerializer的时候,可以使用model来指定模型类,使用fields来指定具体生成的字段,使用exclude可以明确排除掉哪些字段,使用readonlyfields来指明只读字段,即仅用于序列化输出的字段。我们还可以使用extra_kwargs参数为 ​ModelSerializer​添加或修改原有的选项参数。

序列化对象的创建​:

序列化器类(instance=<实例对象>, data=<数据>, **kwargs)


如果是想将对象序列化,那么将其赋值给instance;

如果是数据校验,那么将数据赋值给data。


5.4.3序列化功能

将实例对象转换为字典数据:

a.序列化单个对象。

b.序列化多个对象。(其实就是在序列化单个对象的基础上多加了一个参数many=True)

c.关联对象的嵌套序列化。(详情见本文标题4)


json.dumps()是将字典转换成json字符串

json.loads()是将json字符串转换成字典数据


5.4.4反序列化功能

1.数据校验

我们可以调用 ​is_valid()​来进行数据的校验,我们还可以​补充额外的验证​:a.先写一个函数(如about_django)封装补充验证的功能,然后在字段中添加 ​validators​参数,如下:

btitle = serializers.CharField(...,validators=[about_django])

b.在序列化器中定义一个方法 ​validate_<field_name>​,来对 ​<field_name>​字段进行验证。

def validate_btitle(self, value):    ...    return value

c.在序列化器中定义 ​validate​方法进行补充验证(结合多个字段内容验证)

def validate(self, attrs):    # 此处的attrs是一个字典类型的数据,创建序列化器对象的时候,传入的data数据    ...    return attrs

2.数据保存(新增&更新)

在创建序列化对象的时候如果只是传入了data参数,那么就会调用create方法进行数据保存;如果还传入了instance对象,那么就会调用update方法进行数据的更新操作。

注意:校验通过之后,要调用 ​serializer.save()​进行数据的保存。

5.5视图类

5.5.1功能

1.使用序列化器(数据校验,数据保存,数据的序列化)。

2.进行数据库的相关查询。

5.5.2视图基类

5.5.2.1APIView

是View类的子类,在View类的基础上添加了一些额外的功能。

功能​:

1.视图中​request​对象不再是Django中原始的HttpRequest类的对象,而是DRF框架封装的Request类的对象。


request.data保存的是解析之后的请求体的数据,并且已经解析成了字典或类字典,相当于包含Django原始request对象中的request.body/request.POST/request.FILES

request.query_params保存解析之后的查询字符串的数据,并且已经解析成了字典或类字典,相当Django原始request对象中的request.GET


2.​响应​时可以统一返回Response类的对象。

Response类的对象:传入原始的响应数据,会自动根据客户的请求头中 ​Accept​将响应数据转换为对应的格式进行返回,默认是json,仅支持json和html

3.​异常处理​:如果视图中抛出了未处理异常,DRF框架会自动对异常进行处理,并且会把处理之后的错误信息返回给客户端。

4.​高级功能​:认证、权限、限流

5.5.2.2GenericAPIView

是APIView的子类,在APIView的基础上添加操作序列化器和数据库查询的方法。

操作序列化器:

属性​:

serializer_class​(指定视图所使用的序列化器类)

方法​:

get_serializer_class​返回视图所使用的序列化器类​get_serializer​创建视图所使用的序列化器类对象。

数据库查询

属性​:

queryset​(指定视图所使用的查询集)

方法​:

get_queryset​返回视图所使用的查询集​get_object​从视图所使用的查询集中查询指定的对象,默认根据pk进行查询。

其他功能

过滤、分类

通常GenericAPIView配合Mixin扩展类进行使用

5.5.2.3Mixin扩展类

DRF框架提供了5个扩展类,封装了通用增删改查的流程。

ListModelMixin

提供了一个list方法,封装了​获取一组数据​的通用流程。

CreateModelMixin

提供了一个create方法,封装了新增一条数据的通用流程。

RetrieveModelMixin

提供了一个retrieve方法,封装了​获取指定数据​的通用流程。

UpdateModelMixin

提供了一个update方法,封装了更新指定数据的通用流程。

DestroyModelMixin

提供了一个destroy方法,封装了​删除指定数据​的通用流程。

为了方便我们开发RestAPI,DRF框架除了提供APIView和GenericAPIView视图类之外,还提供了一些子类视图类,这些子类视图类同时继承了GenericAPIView和对应的Mixin扩展类,并且提供了对应的请求方法。

5.6视图集

5.6.1概念

将操作同一组资源的处理方法(API接口)放在同一个类中

5.6.2注意点

1.视图集中的处理方法不再以请求方法命名,而是以对应的操作(action)名称命名:list/create/update/retrieve/destroy

2.在进行url配置的时候,要指明请求地址的请求方式和视图集中处理函数之间的对应关系。

url(r'^books/$',views.BookInfoViewSet.as_view({    'get':'list',    'post':'create'}))

5.6.3视图集父类

ViewSet

最基础的父类,我们一般不使用

GenericViewSet

继承自ViewSetMixin和GenericAPIView,可以配合Mixin扩展类提供对应的处理方法。

ModelViewSet

继承自GenericViewSet和5个对应Mixin扩展类。如果视图集中一次性想要提供5个接口的时候,我们可以继承此父类。

ReadonlyModelViewSet

继承自GenericViewSet和ListModelMixin, RetrieveModelMixin。如果视图集中只想提供list和retrieve接口的时候,可以继承此父类。

5.6.4视图集中添加额外的处理方法

1.直接在视图集定义额外的处理方法即可

2.在进行url配置的时候也要指定请求地址请求方式和处理函数之间的对应的关系。

5.6.5视图集对象的action属性

视图集对象的action属性是一个字符串,我们可以根据action获取所要执行的是哪一种操作。

使用场景​:

根据不同的操作返回不同的序列化器类和不同的查询集,重写 ​get_serializer_class​和 ​get_queryset​方法。

def get_serializer_class(self):

if self.action == 'list':

# 返回list操作对应的序列化器类

elif self.action == 'latest':

# 返回latest操作对应的序列化器类

else:

# 返回其他操作对应的序列化器类



def get_queryset(self):

if self.action == 'list':

# 返回list操作使用的查询集

elif self.action == 'latest':

# 返回latest操作使用的查询集

else:

# 返回其他操作所使用的查询集

5.6.6路由Router

作用

配合视图集进行使用,动态生成视图集中处理函数的url配置项。

使用

1.创建Router类的对象

from restframe_work.routers import SimpleRouter,DefaultRouterrouter = SimpleRouter()

2.注册视图集

router.register(prefix,viewset,base_name)


prefix 该视图集的路由前缀

viewset 视图集

base_name 路由名称的前缀


3.将生成的url配置项列表添加urlpatterns中

urlpatterns += router.urls
视图集额外处理方法url配置项的生成

需要给对应的方法添加action装饰器。

@action(methods=['get'], detail=False)def latest(self, request):    ...    return Response(...)


methods 声明该action对应的请求方式,列表传递

detail 声明该action的路径是否与单一资源对应。举个例子:True表示的是xxx/\/action方法名,而False表示的是xxx/action方法名


6.高级功能

6.1分页

我们可以在配置文件中设置全局的分页方式

REST_FRAMEWORK = {    'DEFAULT_PAGINATION_CLASS':  '<全局分页类>',    'PAGE_SIZE': <页容量>  }

6.1.1分页类

PageNumberPagination

前端访问网址的形式需要在后面跟

?page=<页码>

LimitOffsetPagination

前端访问网址的形式需要在后面跟

?offset=<偏移量>&limit=<数据条数>

6.1.2自定义分页类

class StandardResultPagination(PageNumberPagination):    # 指定页容量    page_size = 3    # 指定获取分页数据时,传递的也容量参数名称    page_size_query_param = 'page_size'    # 指定最大页容量    max_page_size = 5

前端访问网址的形式需要在后面跟

?page=<页码>&page_size=<页容量>

视图关闭分页pagination_class = None

6.2异常处理

可以设置DRF框架的默认异常处理,也可以自定义异常处理函数。

def exception_handler(exc, context):

# 先调用DRF框架的默认异常处理函数

response = drf_exception_handler(exc, context)



if response is None:

view = context['view']

# 补充数据库的异常处理

if isinstance(exc, DatabaseError):

print('[%s]: %s' % (view, type(exc)))

response = Response({'detail': '服务器内部错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)



return response

然后需要在配置文件中声明自定义的异常处理。

REST_FRAMEWORK = {    'EXCEPTION_HANDLER': 'booktest.utils.exceptions.exception_handler'}

6.3其他

认证​:可以进行DRF框架默认全局认证方案设置,也可以对其进行修改,还可以指定某个视图的认证方案。

权限​:区分的是认证与未认证的用户。可以进行DRF框架默认全局权限设置,也可对其进行修改,还可以指定某个视图的权限控制设置,甚至可以自定义权限控制类。权限和认证通常是一起使用的。

限流​:注意,是对用户访问API接口​频次​进行限制。我们既可以针对匿名用户和认证用户进行统一限流设置,也可以分开进行限流设置。

过滤​:需要先安装django-filter并进行注册设置,再在视图中通过 ​filter_fields​设置过滤字段。​排序​:设置filter_backends并通过 ​ordering_fields​设置排序字段。

自动生成接口文档​:生成的接口文档并不全面,强烈建议,自己写接口文档。

重点内容回顾-DRF_数据_03