Django是一个优秀的Python web框架,被众多python开发者所喜爱。新开这个Django专栏,并不是从零开始详细使用Django框架来开发web网页,而是用来开发api。前后分离是当前的技术栈潮流

1.serializers序列化
2.分页查询
3.request
4.实际案例:嘴臭生成器

1.serializers序列化

序列化帮助我们提供了

  • 数据校验
  • 序列化(即字符串化,网络传输都是以字符串形式传输)
  1. 创建一个serializers.py文件

在APP目录下创建一个名为serializers.py文件,用于描述序列化逻辑
PS:序列化时一定要继承serializers.ModelSerializer 序列化类,不然会出很多问题,e.g., post请求时,缺少的create方法;put请求时,缺少update方法。

  • 最简单的一个序列化案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    from rest_framework import serializers
    from . import models

    class NewCategorySerializer(serializers.ModelSerializer):
    class Meta:
    model = models.Category # 声明模型名
    """
    fields表示要展示的字段,有两种写法:
    写法一:
    fields = "__all__":表示全部展示Category模型里的所有字段
    写法二:
    fields = ['id','name',...]:将想要展示的Category模型里的特定字段添加到数组中
    """
    fields = ['id','name']
    depth = 1 # 此字段表示查看嵌套几层的数据【推荐0-3】,不建议太大,性能损耗
  • 序列化深入:source用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from rest_framework import serializers
from . import models
class ArticleSerializer(serializers.ModelSerializer):
category_txt = serializers.CharField(source='category.name',required=False)
x1 = serializers.SerializerMethodField()

status_txt = serializers.CharField(source='get_status_display',required=False)

x2 = serializers.SerializerMethodField()
class Meta:
model = models.Article
# fields = "__all__"
fields = ['id','title','summary','content','category','category_txt','x1','status','status_txt','x2']
# depth = 1

def get_x1(self,obj):
return obj.category.name

def get_x2(self,obj):
return obj.get_status_display()

对序列化深入的详细说明

1
2
3
4
5
6
7
8
9
10
# fields添加展示字段方式一:直接使用定义的models的字段
fields = ['title','summary','content','category']

# fields添加展示字段方式二:使用source,引用category模型的name字段
category_txt = serializers.CharField(source='category.name',required=False)

# fields添加展示字段方式三:自定义函数
x1 = serializers.SerializerMethodField() # 先定义x1,并声明为序列化方法字段
def get_x1(self,obj): # 函数命名方式:get_自定义的字段名
return obj.category.name
  1. 创建一个views.py实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
from .serializers import ArticleSerializer
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import Category, Article


class ArticleView(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if not pk:
queryset = Article.objects.all()
ser = ArticleSerializer(instance=queryset, many=True)
return Response(ser.data)
article_object = Article.objects.filter(id=pk).first()
ser = ArticleSerializer(instance=article_object, many=False)
return Response(ser.data)

def post(self, request, *args, **kwargs):
ser = ArticleSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
return Response(ser.errors)

def put(self, request, *args, **kwargs):
pk = kwargs.get('pk')
article_object = Article.objects.filter(id=pk).first()
ser = ArticleSerializer(instance=article_object, data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
return Response(ser.errors)

def patch(self, request, *args, **kwargs):
"""局部"""
pk = kwargs.get('pk')
article_object = Article.objects.filter(id=pk).first()
ser = ArticleSerializer(instance=article_object, data=request.data, partial=True)
if ser.is_valid():
ser.save()
return Response(ser.data)
return Response(ser.errors)

def delete(self, request, *args, **kwargs):
pk = kwargs.get('pk')
Article.objects.filter(id=pk).delete()
return Response('删除成功')
  1. urls.py进行映射
1
2
3
4
5
6
7
8
9
10
# -*- coding:utf-8 -*-
from django.conf.urls import url
from django.urls import path, re_path
from . import views # 导入views文件中的视图函数(标准写法)

urlpatterns = [
# get获取列表;post增加数据
re_path(r'^drf/article/$', views.ArticleView.as_view()),
re_path(r'^drf/article/(?P<pk>\d+)/$', views.ArticleView.as_view()),
]

2.分页查询

drf中的分页查询有两种:

  • PageNumberPagination类:访问url形如page/view/article/?page=2
  • LimitOffsetPagination类:访问url形如page/article/?offset=0&limit=3

PageNumberPagination类

views.py文件:必须重写父类PageNumberPagination,重设每页展示数据量,不设置,则默认不分页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from .serializers import PageArticleSerializer
from rest_framework.pagination import PageNumberPagination


# 类似于Java中的接口interface,必须重写父类方法
class NewPageNumberPagination(PageNumberPagination):
page_size = 3 # 重写,每页展示数据数


class PageViewArticleView(APIView):
def get(self, request, *args, **kwargs):
queryset = Article.objects.all()
"""
# 方式一:仅数据
# 分页对象
page_object = NewPageNumberPagination()
# 调用 分页对象.paginate_queryset方法进行分页,得到的结果是分页之后的数据
# result就是分完页的一部分数据
result = page_object.paginate_queryset(queryset, request, self)
# 序列化分页之后的数据
ser = PageArticleSerializer(instance=result, many=True)
return Response(ser.data)
"""

# 方式二:数据 + 分页信息
"""
page_object = NewPageNumberPagination()
result = page_object.paginate_queryset(queryset, request, self)
ser = PageArticleSerializer(instance=result, many=True)
return page_object.get_paginated_response(ser.data)
"""
# 方式三:数据 + 部分分页信息

page_object = NewPageNumberPagination()
result = page_object.paginate_queryset(queryset, request, self)
ser = PageArticleSerializer(instance=result, many=True)
return Response({'count': page_object.page.paginator.count, 'result': ser.data})

LimitOffsetPagination分页

views.py文件:必须重写父类LimitOffsetPagination,限制每页最大偏移量。不设置,有可能会被黑客攻击
比如:有一个黑衣人调用api后,修改请求url:offset=0&limit=200000000…,如此庞大的数据量一下子加载到内存中,服务器直接宕机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 分页方式二:
from rest_framework.pagination import LimitOffsetPagination
from .serializers import PageArticleSerializer


class HulaLimitOffsetPagination(LimitOffsetPagination):
# 覆盖重写父类max_limit属性,设置最大数据量
max_limit = 2


class PageArticleView(APIView):
def get(self, request, *args, **kwargs):
queryset = Article.objects.all()
# 声明分页类
page_object = HulaLimitOffsetPagination()
result = page_object.paginate_queryset(queryset, request, self)
ser = PageArticleSerializer(instance=result, many=True)
return Response(ser.data)

3. request

DRF引入了一个扩展Django常规 HttpRequest 对象的 Request 对象,并提供了更灵活的请求 解析能力。Request 对象的核心功能是 request.data 属性

  • request.headers 获取请求头,将其转化为字典dict
  • request.method 获取请求方法
  • request.data 获取post请求携带参数,为字典类型
  • request.query_params 获取get请求的查询字符串,为<QueryDict: {‘offset’: [‘0’], ‘limit’: [‘3’]}>类型
  • request.user 判断当前用户认证情况(匿名或者已登录)

4.实际案例:嘴臭生成器

  • urls.py:路由设置
1
2
3
4
5
6
7
8
9
10
11
# -*- coding:utf-8 -*-
from django.conf.urls import url
from django.urls import path, re_path
from . import views # 导入views文件中的视图函数(标准写法)

urlpatterns = [
path('demo/', views.demo, name='demo'),

# 嘴臭生成器:offset,limit分页查询字符串形式为: ndsl/动态id/?offset=0&limit=3
re_path(r'^ndsl/(?P<pk>\d+)/', views.Nmsl8.as_view()),
]
  • model.py:orm模型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from django.db import models


# 嘴臭表
class Nmsl(models.Model):
category_choices = (
(1, '莲花模式'),
(2, '仙人模式'),
(3, '气急败坏'),
(4, 'NMSL')
)
level = models.IntegerField(verbose_name="嘴臭限度", choices=category_choices, default=1)
content = models.TextField(verbose_name="嘴臭内容", blank=False)
create_time = models.DateTimeField(verbose_name="嘴臭时间", auto_now_add=True)
objects = models.Manager()
  • serializers.py:序列化函数

获取models模型中choices的值,参考文章: https://blog.csdn.net/qq_41854273/article/details/84987899

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# -*- coding:utf-8 -*-
from rest_framework import serializers
from . import models


# 嘴臭生成器序列化
class NmslAndNdslSerializer(serializers.ModelSerializer):
# level = serializers.SerializerMethodField()

class Meta:
model = models.Nmsl
fields = "__all__"
depth = 1

# 获取models模型中choices的值,参考文章https://blog.csdn.net/qq_41854273/article/details/84987899
# def get_level(self, obj):
# return obj.get_level_display()
  • views.py:视图渲染
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import json

from django.forms import model_to_dict
from rest_framework import mixins
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from django.shortcuts import render
from django.http import JsonResponse
from django.views import View


from .models import Category, Article, Nmsl
from .form import SaveForm


# 嘴臭生成器模块
from rest_framework.pagination import LimitOffsetPagination
from .serializers import NmslAndNdslSerializer


class NmslLimitOffsetPagination(LimitOffsetPagination):
# 覆盖重写父类max_limit属性
max_limit = 2


class Nmsl8(APIView):
def get(self, request, *args, **kwargs):
queryset = Nmsl.objects.all()
print(request.headers)
print(request.method)
print(request.path)
# 声明分页类
page_object = NmslLimitOffsetPagination()
result = page_object.paginate_queryset(queryset, request, self)
ser = NmslAndNdslSerializer(instance=result, many=True)
return Response(ser.data)

def post(self, request, *args, **kwargs):
ser = NmslAndNdslSerializer(data=request.data)
print(request.data)
if ser.is_valid():
ser.save()
return Response({"status": "success", "content": request.data.get('content')})
else:
return Response({"status": "failed"})

def put(self, request, *args, **kwargs):
"""
put全部更新
:param request:
:param args:
:param kwargs:
:return:
"""
pk = kwargs.get('pk')
article_object = Nmsl.objects.filter(id=pk).first()
ser = NmslAndNdslSerializer(instance=article_object, data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
return Response(ser.errors)

def patch(self, request, *args, **kwargs):
"""局部更新"""
pk = kwargs.get('pk')
article_object = Nmsl.objects.filter(id=pk).first()
ser = NmslAndNdslSerializer(instance=article_object, data=request.data, partial=True)
if ser.is_valid():
ser.save()
return Response(ser.data)
return Response(ser.errors)

def delete(self, request, *args, **kwargs):
pk = kwargs.get('pk')
Nmsl.objects.filter(id=pk).delete()
return Response('删除成功')
  • 请求url
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
get请求:
url: http://127.0.0.1:8001/nmsl/ndsl/10/?offset=3&limit=5
PS:动态id为10不会影响get请求,只是在put,patch,delete时用来操作具体那个id。
get请求是分页查询,结果是由offset与limit决定的


post请求:创建一组新数据
url:http://127.0.0.1:8001/nmsl/ndsl/10/
请求参数:
data={ "level":4,
"content":"NMSL,狗贼"
}


pathch请求:局部更新
url:http://127.0.0.1:8001/nmsl/ndsl/10/
请求参数:将id为10的数据的content更新值
data={
"content":"NMLGB"
}


put请求:全部更新
url:http://127.0.0.1:8001/nmsl/ndsl/10/
请求参数:将id为10的数据的content以及level全部更新
data={
"level":2,
"content":"你今晚biss"
}


delete请求:删除(直接删除id为10的数据行)
url:http://127.0.0.1:8001/nmsl/ndsl/10/

 评论

联系我 | Contact with me

Copyright © 2019-2020 谁知你知我,我知你知深。此恨经年深,比情度日久

博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议