初步使用serializer
- 使用serializers的好处
- 1.图片路径返回时,普通的view需要手动添加补全路径,drf已封装
- 2.无论是django.core的serializer还是django.forms.models的model_to_dict都已经被serializer封装替代,使用比较方便
- 3.drf的自带文档功能,需要serializer和coreapi的支持
- 4.代替了form验证的功能
- serializer
1
2
3
4
5
6
7
8
9from rest_framework import serializers
from .models import Goods
class GoodsSerializer(serializers.ModelSerializer):
name = serializers.CharField(required=True, max_length=100)
click_num = serializers.IntegerField(default=0)
class Meta:
model = Goods
fields = ('name', 'click_num') - views
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15from .models import Goods
from .serializers import GoodsSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class GoodsListView(APIView):
"""
List goods
"""
def get(self, request):
goods = Goods.objects.all()[:10]
goods_serializer = GoodsSerializer(goods, many=True)
return Response(goods_serializer.data) - urls
1
2# 商品列表页面
path(r'goods/', GoodsListView.as_view(), name="goods-list"),
细枝末节
- 1.保存数据
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# 在serializer中重写create
class GoodsSerializer(serializers.ModelSerializer):
name = serializers.CharField(required=True, max_length=100)
click_num = serializers.IntegerField(default=0)
class Meta:
model = Goods
fields = ('name', 'click_num')
def create(self, validated_data):
"""
Create and return a new `Snippet` instance, given the validated data.
"""
return Goods.objects.create(**validated_data)
class GoodsListView(APIView):
"""
List goods
"""
def get(self, request):
goods = Goods.objects.all()[:10]
goods_serializer = GoodsSerializer(goods, many=True)
return Response(goods_serializer.data)
def post(self, request):
serializer = GoodsSerializer(data=request.data)
if serializer.is_valid():
# save会去调用create
serializer.save()
# 保存成功返回201
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - 2 fileds = “__all__”即可序列化全部字段
- 3.外键序列化需要嵌套外键自身的serializer
1
2
3
4
5
6
7
8
9
10
11
12class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = GoodsCategory
fields = '__all__'
class GoodsSerializer(serializers.ModelSerializer):
# 嵌套序列化外键
category = CategorySerializer()
class Meta:
model = Goods
fields = '__all__'
Serializer Fields
- core
- read_only
- 不在创建和更新的操作中,在序列化列表时
- write_only
- 序列化时不使用这个字段,在创建和更新反序列化时使用
- required
- 反序列化不需要此字段
- default
- allow_null
- source
- error_message
- label
- help_text
- initial
- style
- read_only
- 各种字段请查看官方链接
最简单的view-genericapiview/viewSet
- Apiview并不是最上流的view,还有更简单的view
1
2
3
4
5
6
7
8
9
10from rest_framework import mixins
from rest_framework import generics
class GoodsListView(mixins.ListModelMixin, generics.GenericAPIView):
queryset = Goods.objects.all()[:10]
serializer_class = GoodsSerializer
# list在listModelMixin中,帮助我们分页,调用序列化等
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs) - 封装好的view
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25class CreateAPIView(mixins.CreateModelMixin,
GenericAPIView):
"""
Concrete view for creating a model instance.
"""
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class ListAPIView(mixins.ListModelMixin,
GenericAPIView):
"""
Concrete view for listing a queryset.
"""
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
class RetrieveAPIView(mixins.RetrieveModelMixin,
GenericAPIView):
"""
Concrete view for retrieving a model instance.
"""
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs) - viewSet
1
2
3
4
5
6
7from rest_framework import viewsets
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
queryset = Goods.objects.all()
serializer_class = GoodsSerializer
pagination_class = GoodsPagination - 两种路由注册方式:
- 1.正常注册
1
2
3
4
5
6from goods.views import GoodsListViewSet
goods_list = GoodsListViewSet.as_view({
'get': 'list',
'post': 'create'
})
- path(r'goods/', goods_list, name="goods-list"), - 2.使用router
1
2
3
4
5
6
7from rest_framework.routers import DefaultRouter
router = DefaultRouter()
# 配置goods的url(把注册的东西转换为url的配置)
router.register(r'goods', GoodsListViewSet)
path(r'', include(router.urls))
# 它会自动把get转到list,post转到create等
- 1.正常注册
分页
- 在setting里配置REST_FRAMEWORK
1
2
3
4
5REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
# Pagination
'PAGE_SIZE': 10,
} - 这里可以看出可以简单自定义继承PageNumberPagination的分页
1
2
3
4
5class ArticlePagination(PageNumberPagination):
page_size = 4 # 表示每页的默认显示数量
page_size_query_param = 'page_size' # 表示url中每页数量参数
page_query_param = 'p' # 表示url中的页码参数
max_page_size = 100 # 表示每页最大显示数量,做限制使用,避免突然大量的查询数据,数据库崩溃 - 在view中指定pagination_class即可
过滤
1.通过sql进行简单过滤
1
2
3
4
5
6
7
8
9
10
11class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
def get_queryset(self):
self.queryset = Goods.objects.all() # 这里只是帮我们拼凑了sql脚本,并没有执行,只有在for循环的时候执行
price_min = self.request.query_params.get("price_min", 0)
if price_min:
self.queryset = self.queryset.filter(shop_price__gt=int(price_min))
return self.queryset2.通过django-filter
1
2
3
4
5
6
7
8
9from django_filters.rest_framework import DjangoFilterBackend
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
queryset = Goods.objects.all() # 这里只是帮我们拼凑了sql脚本,并没有执行,只有在for循环的时候执行
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
filter_backends = (DjangoFilterBackend, )
filter_fields = ('name', 'shop_price')通过rest_framework的seachfilter进行过滤
1
2
3
4
5
6
7
8
9from .filters import GoodsFilter
from rest_framework import filters
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
queryset = Goods.objects.all() # 这里只是帮我们拼凑了sql脚本,并没有执行,只有在for循环的时候执行
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
filter_backends = (DjangoFilterBackend, filters.SearchFilter)排序过滤
1
filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
通过django_filter.rest_framework.FielterSet自定义(新建filter文件夹)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21from .models import Goods
import django_filters
class GoodsFilter(django_filters.rest_framework.FilterSet):
"""商品的过滤类"""
price_min = django_filters.NumberFilter(field_name="shop_price", lookup_expr='gte') # greater than or equal to
price_max = django_filters.NumberFilter(field_name="shop_price", lookup_expr='lte') # less than or equal to
name = django_filters.CharFilter(field_name='name', lookup_expr='icontains')
class Meta:
model = Goods
fields = ["name", "price_min", "price_max"]
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
queryset = Goods.objects.all() # 这里只是帮我们拼凑了sql脚本,并没有执行,只有在for循环的时候执行
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
filter_backends = (DjangoFilterBackend, filters.SearchFilter)
filter_class = GoodsFilter
# 不限于某个字段,只要配置进了search_fields就可以模糊搜索
search_fields = ('name', 'goods_brief', 'goods_desc')