serializers

初步使用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
    9
    from 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
    15
    from .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
    12
    class 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
  • 各种字段请查看官方链接

最简单的view-genericapiview/viewSet

  • Apiview并不是最上流的view,还有更简单的view
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from 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
    25
    class 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
    7
    from 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
      6
      from 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
      7
      from rest_framework.routers import DefaultRouter

      router = DefaultRouter()
      # 配置goods的url(把注册的东西转换为url的配置)
      router.register(r'goods', GoodsListViewSet)
      path(r'', include(router.urls))
      # 它会自动把get转到list,post转到create等

分页

  • 在setting里配置REST_FRAMEWORK
    1
    2
    3
    4
    5
    REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    # Pagination
    'PAGE_SIZE': 10,
    }
  • 这里可以看出可以简单自定义继承PageNumberPagination的分页
    1
    2
    3
    4
    5
    class 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
    11
    class 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.queryset
  • 2.通过django-filter

    1
    2
    3
    4
    5
    6
    7
    8
    9
    from 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
    9
    from .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
    21
    from .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')

跨域问题

分享到