mahsiaoko / backend

0 stars 0 forks source link

后端列表页的实现 #6

Open mahsiaoko opened 5 years ago

mahsiaoko commented 5 years ago

使用django的View

from .models import Goods
from django.http import HttpResponse
import json

class GoodsListView1(View):
    def get(self, request):
        goods = Goods.objects.all()
        json_list = []
        for good in goods:
            json_dict = {}
            json_dict['name'] = good.name
            json_dict['category'] = good.category.name
            json_dict['market_price'] = good.market_price
            json_list.append(json_dict)
        return HttpResponse(json.dumps(json_list), content_type="application/json")

json.dumps()将字典形式的数据转为字符串。 image 很方便的实现了列表返回,但是存在这样的问题,

django本身的model_to_dict:

from django.views.generic.base import View
from .models import Goods
from django.http import HttpResponse
import json
from django.forms.models import model_to_dict

class GoodsListView1(View):
    def get(self, request):
        goods = Goods.objects.all()
        json_list = []
        for good in goods:
            json_dict = model_to_dict(good)
            json_list.append(json_dict)
        return HttpResponse(json.dumps(json_list), content_type="application/json")

报错:Object of type ImageFieldFile is not JSON serializable

django的serializer序列化model

from django.views.generic.base import View
from .models import Goods
from django.http import HttpResponse
from django.core import serializers

class GoodsListView1(View):
    def get(self, request):
        goods = Goods.objects.all()
        json_data = serializers.serialize("json", goods)
        return HttpResponse(json_data, content_type="application/json")

此时序列化不会出现问题,当然返回的Response还可以表述为:

from django.views.generic.base import View
from .models import Goods
from django.http import JsonResponse
from django.core import serializers
import json

class GoodsListView1(View):
    def get(self, request):
        goods = Goods.objects.all()[:10]
        json_data = serializers.serialize("json", goods)
        json_data = json.loads(json_data)
        # 为了允许非字典能够序列化,需要使safe = False
        return JsonResponse(json_data, safe=False)

json.loads()用于将字符串形式的数据转化为字典 虽然django本身就可以实现序列化,但是功能单一,很多无法实现。

mahsiaoko commented 5 years ago

drf的apiview实现列表页

django:Form<-->ModelForm drf:serializer<-->ModelSerializer ModelSerializer实现商品列表页

serializer

在views.py中:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Goods
class GoodsListView(APIView):
    """
    List all goods
    """

    def get(self, request, format=None):
        goods = Goods.objects.all()[:10]
        # 此处many=True表示可能是一个列表,是一个querySetDict,如果是单个good的话,不用写
       # many=True,会序列化为一个数组对象
        goods_serializer = GoodsSerializer(goods, many=True)
        return Response(goods_serializer.data)

    # 接收前端传递来的数据,保存到数据库中
    def post(self, request, format=None):
        # drf会把数据取出来放到data中
        serializer = GoodsSerializer(data=request.data)
        if serializer.is_valid():
            # serializer.save()会调用GoodsSerializer中的create方法
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

在serializers.py中,针对Goods,有如下操作:

from rest_framework import serializers
from .models import Goods
# 新建一个model来映射字段
class GoodsSerializer(serializers.Serializer):
    name = serializers.CharField(required=True, max_length=100)
    click_num = serializers.IntegerField(default=0)
    goods_front_image = serializers.ImageField()

    # 往数据库中保存
    # validated_data保存有上面定义的字段
    def create(self, validated_data):
        """
        Create and return a new `Good` instance, given the validated data.
        """
        return Goods.objects.create(**validated_data)

ModelSerializer

在serializers.py中,针对Goods,有如下操作:

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = GoodsCategory
        fields = "__all__"

class GoodsSerializer(serializers.ModelSerializer):
    # category是外键,如果想获得详细信息,需要以下方式
    # 覆盖默认的category,实例化CategorySerializer,
    # category = CategorySerializer()

    class Meta:
        model = Goods
        # fields = ("name", "click_num","goods_sn", "sold_num", "fav_num", "goods_num", "market_price",
        #           "shop_price", "goods_brief", "goods_desc", "is_new", "is_hot", "add_time")

        # 直接取出所有字段使用 __all__
        fields = "__all__"

使用ModelSerializer可以省略字段的定义,直接实现model的序列化,此处外键会直接显示为id,想显示外键内容,可以按照上面的所示。 在views.py中直接使用之前的,无需改变。

mahsiaoko commented 5 years ago

对views.py中的代码进一步的简化

from rest_framework.response import Response
from rest_framework import mixins
from rest_framework import generics
from .serializers import GoodsSerializer
class GoodsListView(mixins.ListModelMixin,mixins.CreateModelMixin, generics.GenericAPIView):
    """
    使用mixins.ListModelMixin实现商品列表页;
    使用generics.GenericAPIView继承了APIView
    """
    queryset = Goods.objects.all()[:10]
    serializer_class = GoodsSerializer
    # 重写get函数,不写的话get方法就默认不允许
    # self.list的list在mixins.ListModelMixin中
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
    # 重写post方法,默认不允许
   # post的话,使用的是mixins.CreateModelMixin
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

上面的代码可以进一步的简化,在generics中,有一个ListAPIView,其详细代码为:

class ListAPIView(mixins.ListModelMixin,
                  GenericAPIView):
    """
    Concrete view for listing a queryset.
    """
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

可以看出, ListAPIView继承了mixins.ListModelMixin和GenericAPIView,而且覆写了get,所以可以直接在代码中继承ListAPIView,如下:

class GoodsListView(generics.ListAPIView):
    """
    使用mixins.ListModelMixin实现商品列表页;
    使用generics.GenericAPIView继承了APIView
    """
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
mahsiaoko commented 5 years ago

drf实现列表分页功能

分页,针对特定的app来定制分页功能

from rest_framework.pagination import PageNumberPagination

class GoodsPagination(PageNumberPagination):
    page_size = 20
    page_size_query_param = 'page_size'
    page_query_param = 'p'
    max_page_size = 100

class GoodsListView(generics.ListAPIView):
    """
    使用mixins.ListModelMixin实现商品列表页;
    使用generics.GenericAPIView继承了APIView
    """
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination