Django rest framwork 快速使用

RESTful API : 面向资源编程

DEMO DDjango rest framework

1
2
3
pip install djangorestframework
pip install markdown # Markdown support for the browsable API.
pip install django-filter # Filtering support look docs

快速使用

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
# step 1:注册 App -> setting.py
INSTALLED_APPS = [
...
'rest_framework', # <---
]
# step 2:注册路由 api--->urls.py(单独App)
from rest_framework import routers
from . import views

router = routers.DefaultRouter()
router.register('users',Views.UserInfoViewSet)

urlpatterns = [
# 登录功能
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
url(r'^'),include(router.urls)),
]

# step 3:view.py
from app01.models import *
from rest_framework.viewsets import ModelViewSet
from rest_framework.serializers import HyperlinkedModelSerializer

# Create your views here.

class UsersSerializer(HyperlinkedModelSerializer):
''' rest api 数据定制 指定显示的数据 '''
class Meta:
model = User
fields = ('id','username') # 字段
# exclude = ('password',) # 除这个字段以外
depth = 0 # 0 <= depth <= 10 查询外键 0 只查自己的表 1 关联的下一层也会拿到 ...

class UsersViewSet(ModelViewSet):
queryset = User.objects.all().order_by('-id')
serializer_class = UsersSerializer # 验证数据库操作 相当于 Form的功能

CBV

  • urls.py
1
2
3
4
5
urlpatterns = [
url(r'user/$', views.UserView.as_view()), # CBV
# url(r'user/(?P<pk>[0-9]+)/$',views.UserDetail.as_view()), # CBV
url(r'user/(\d+)/$', views.UserDetail.as_view()), # CBV
]
  • view.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
from rest_framework.views import APIView
from app01 import serializers
from rest_framework.parsers import JSONParser # json -> loads

class UserView(APIView):
def get(self, request, *args, **kwargs):
""" 获取多条数据 """
data_list = User.objects.all()

# 1. django 序列化
# from django.core import serializers
# data = serializers.serialize('json',data_list)
# return HttpResponse(data)

# 2. rest framework 序列化 + form 验证 + 自定义
serializer = serializers.MySerializer(instance=data_list, many=True) # many -> 单条 or 多条
# return HttpResponse(json.dumps(serializer.data,ensure_ascii=False)) # 正常显示中文
return JsonResponse(serializer.data,safe=False,json_dumps_params={"ensure_ascii":False})

def post(self, request, *args, **kwargs):
""" 创建数据 """
# old
# print(request.data)
# Blog.objects.create(**request.data)
# rest framework
data = JSONParser().parse(request)
serializer = serializers.MySerializer(data=data)
if serializer.is_valid():
# print(serializer.data)
# print(serializer.errors)
# print(serializer.validated_data)
# 如果有 instance,则执行 update 方法;否则执行 create
serializer.save()
return HttpResponse('...')


class UserDetail(APIView):
def get(self, request, nid): # *args,**kwargs -> pk`
""" 获取单条数据 """
obj = User.objects.filter(nid=nid).first()
serializer = serializers.MySerializer(instance=obj)
return JsonResponse(serializer.data, safe=False, json_dumps_params={"ensure_ascii": False})

def put(self, request, nid): # *args,**kwargs -> pk`
''' 修改单条数据 '''
obj = User.objects.filter(nid=nid).first()
data = JSONParser().parse(request)
serializer = serializers.MySerializer(instance=obj,data=data)
if serializer.is_valid():
serializer.save()
return HttpResponse(200)
# TODO

def delete(self, request, nid): # *args,**kwargs -> pk`
""" 删除数据 """
obj = User.objects.filter(nid=nid).delete()
return HttpResponse(status=204)
  • new file serializers.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
from rest_framework import serializers
from app01 import models


class MySerializer(serializers.Serializer):
nid = serializers.IntegerField(read_only=True)
username = serializers.CharField(max_length=64)
password = serializers.CharField(max_length=32)
email = serializers.CharField(max_length=32)

# 和 Form 表单一样
def validate_username(self, value):
return value

def validate_email(self, value):
return value

def update(self, instance, validated_data):
instance.name = validated_data['name']
instance.user = validated_data['user']
instance.save()

def create(self, validated_data):
models.User.objects.create(**validated_data)

总结

  • 2 个 url
  • 5 个 方法

最多进行跨表查询,综合数据展示出来
参考

DRF doc

1
2
3
from rest_framework.documentation import include_docs_urls
# urls.py
url(r'docs/', include_docs_urls(title="example title"))

Django View

使用Django序列化数据

1
2
3
4
5
6
from django.views.generic.base import View, ListView, DateDetailView, DeleteView, DatailView, TemplateView
# django 序列化
from django.forms.models import model_to_dict
from dhango.core.serializers import serialize
json_data = serialize('json', <query>)
from django.http import JsonResponse

DRF view

Serializer

数据序列化,如果需要序列化外键的数据就再创建一个Serializer.

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
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES


class SnippetSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(required=False, allow_blank=True, max_length=100)
code = serializers.CharField(style={'base_template': 'textarea.html'})
linenos = serializers.BooleanField(required=False)
language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')

def create(self, validated_data):
"""
Create and return a new `Snippet` instance, given the validated data.
"""
return Snippet.objects.create(**validated_data)

def update(self, instance, validated_data):
"""
Update and return an existing `Snippet` instance, given the validated data.
"""
instance.title = validated_data.get('title', instance.title)
instance.code = validated_data.get('code', instance.code)
instance.linenos = validated_data.get('linenos', instance.linenos)
instance.language = validated_data.get('language', instance.language)
instance.style = validated_data.get('style', instance.style)
instance.save()
return instance

ModelSerializer

这个可以把所有的字段给省略掉,create,update也可以省掉

APIView

数据列表,继承自View

Using mixins | generics

使用mixinsgenerics更高级的封装来更容易的写接口,继承generics这个文件里面的方法,可以只使用其中某一个功能,但是generics这个不论什么组合都不能少

  • mixins : 数据的操作
  • generics : http的操作
  • drf 就是这些的组合

自定义页码

1
2
3
4
5
6
7
from rest_framework.pagination import PageNumberPagination

class ExamplePagination(PageNumberPagination):
page_size = 10
page_size_query_param = 'page_size'
page_query_param = 'p'
max_page_size = 100

viewsets

各种组合 mixins, GenericViewSet
这个是推荐,常用的,仅限于 view class,它是通过路由绑定。更高级的封装

  • viewsets.GenericViewSet
1
2
3
4
5
class Example(mixins.ListModelMinxin, viewsets.GenericViewSet)
'''GenericViewSet 没有继承 get post 方法,所以还是需要 mixins'''
pass
# 在 urls 里面来绑定函数 action
# https://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/#binding-viewsets-to-urls-explicitly

分析 view

generics 里有各种组合view,

1
2
3
4
5
GenericViewSet(viewset) # drf
GenericAPIView # drf
APIView # drf
View # django
# 越往后的 View 越底层

mixin

1
2
3
4
5
CreateModelMixin
ListModelMixin
UpdateModelMixin
RetrieveModelMixin
DestoryModelMixin

req | rep

DRF 中的requests,response

Filter

1
pip install django-filter

Django Filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import django_filters
from app import model_name

class ExampleFilter(django_filters.rest_framework.FilterSet):
# 大于和小于
price_min = django_filters.NumberFilter(name='price', lookup_expr='gt')
price_max = django_filters.NumberFilter(name='price', lookup_expr='lt')
name = django_fileter.CharFilter(name='name', lookup_expr='icontains')
class Meta:
model = model_name
fields = ['price_min', 'price_max', 'name']


class ModelNameListViewSet(...):
...
filter_class = ExampleFilter

DRF Search Filter | Order Filter

1
2
3
4
5
6
7
8
from rest_framework import filters

ExampleDRFilter(...):
...
filter_backends = (..., filters.SearchFilter)
# 下面的可以加正则
search_fields = ('username', 'eamil',)
ordering_field = ('age', 'add_time')

HTTP

1
2
# 状态
from rest_framework import status