Django REST framework学习记录(二)

四、xadmin后台管理

4.1.xadmin添加富文本插件

(1)xadmin/plugins文件夹下新建文件ueditor.py

# xadmin/plugins/ueditor.py

import xadmin
from xadmin.views import BaseAdminPlugin, CreateAdminView, ModelFormAdminView, UpdateAdminView
from DjangoUeditor.models import UEditorField
from DjangoUeditor.widgets import UEditorWidget
from django.conf import settings



class XadminUEditorWidget(UEditorWidget):
    def __init__(self, **kwargs):
        self.ueditor_options = kwargs
        self.Media.js = None
        super(XadminUEditorWidget,self).__init__(kwargs)


class UeditorPlugin(BaseAdminPlugin):

    def get_field_style(self, attrs, db_field, style, **kwargs):
        if style == 'ueditor':
            if isinstance(db_field, UEditorField):
                widget = db_field.formfield().widget
                param = {}
                param.update(widget.ueditor_settings)
                param.update(widget.attrs)
                return {'widget':XadminUEditorWidget(**param)}
        return attrs

    def block_extrahead(self, context, nodes):
        js  = '<script type="text/javascript" src="%s"></script>' %(settings.STATIC_URL + "ueditor/ueditor.config.js")
        js += '<script type="text/javascript" src="%s"></script>' %(settings.STATIC_URL + "ueditor/ueditor.all.min.js")
        nodes.append(js)

xadmin.site.register_plugin(UeditorPlugin, UpdateAdminView)
xadmin.site.register_plugin(UeditorPlugin, CreateAdminView)

(2)把插件添加到__init__.py里面

# xadmin/plugins/__init__.py

PLUGINS = (
    'ueditor',
)

4.2.url配置

配置xadmin和ueditor的路由

# MxShop/urls.py

import xadmin

from django.urls import path,include

urlpatterns = [
    path('xadmin/', xadmin.site.urls),
    path('ueditor/', include('DjangoUeditor.urls')),
]

4.3.注册app到xadmin后台

四个app下面都新建文件adminx.py,然后分别注册到后台

(1)users/adminx.py

# users/adminx.py

import xadmin
from xadmin import views
from .models import VerifyCode


class BaseSetting(object):
    #添加主题功能
    enable_themes = True
    use_bootswatch = True


class GlobalSettings(object):
    #全局配置,后台管理标题和页脚
    site_title = "仙剑奇侠传"
    site_footer = "http://www.cnblogs.com/derek1184405959/"
    #菜单收缩
    menu_style = "accordion"


class VerifyCodeAdmin(object):
    list_display = ['code', 'mobile', "add_time"]


xadmin.site.register(VerifyCode, VerifyCodeAdmin)
xadmin.site.register(views.BaseAdminView, BaseSetting)
xadmin.site.register(views.CommAdminView, GlobalSettings)

修改app名字为中文

# users/apps.py

from django.apps import AppConfig


class UsersConfig(AppConfig):
    name = 'users'
    #app名字后台显示中文
    verbose_name = "用户管理"

还需要__init__.py中修改默认配置才生效

# users/__init__.py

default_app_config = 'users.apps.UsersConfig'

其它三个app一样的操作

(2)goods/adminx.py

# goods/adminx.py

import xadmin
from .models import Goods, GoodsCategory, GoodsImage, GoodsCategoryBrand, Banner, HotSearchWords
from .models import IndexAd


class GoodsAdmin(object):
    #显示的列
    list_display = ["name", "click_num", "sold_num", "fav_num", "goods_num", "market_price",
                    "shop_price", "goods_brief", "goods_desc", "is_new", "is_hot", "add_time"]
    #可以搜索的字段
    search_fields = ['name', ]
    #列表页可以直接编辑的
    list_editable = ["is_hot", ]
    #过滤器
    list_filter = ["name", "click_num", "sold_num", "fav_num", "goods_num", "market_price",
                   "shop_price", "is_new", "is_hot", "add_time", "category__name"]
    #富文本编辑器
    style_fields = {"goods_desc": "ueditor"}

    #在添加商品的时候可以添加商品图片
    class GoodsImagesInline(object):
        model = GoodsImage
        exclude = ["add_time"]
        extra = 1
        style = 'tab'

    inlines = [GoodsImagesInline]


class GoodsCategoryAdmin(object):
    list_display = ["name", "category_type", "parent_category", "add_time"]
    list_filter = ["category_type", "parent_category", "name"]
    search_fields = ['name', ]


class GoodsBrandAdmin(object):
    list_display = ["category", "image", "name", "desc"]

    def get_context(self):
        context = super(GoodsBrandAdmin, self).get_context()
        if 'form' in context:
            context['form'].fields['category'].queryset = GoodsCategory.objects.filter(category_type=1)
        return context


class BannerGoodsAdmin(object):
    list_display = ["goods", "image", "index"]


class HotSearchAdmin(object):
    list_display = ["keywords", "index", "add_time"]


class IndexAdAdmin(object):
    list_display = ["category", "goods"]


xadmin.site.register(Goods, GoodsAdmin)
xadmin.site.register(GoodsCategory, GoodsCategoryAdmin)
xadmin.site.register(Banner, BannerGoodsAdmin)
xadmin.site.register(GoodsCategoryBrand, GoodsBrandAdmin)

xadmin.site.register(HotSearchWords, HotSearchAdmin)
xadmin.site.register(IndexAd, IndexAdAdmin)

 

# goods/apps.py

from django.apps import AppConfig

class GoodsConfig(AppConfig):
    name = 'goods'
    verbose_name = '商品管理'



# good/__init__.py

default_app_config = 'goods.apps.GoodsConfig'

(3)trade/adminx.py

# trade/adminx.py

import xadmin
from .models import ShoppingCart, OrderInfo, OrderGoods


class ShoppingCartAdmin(object):
    list_display = ["user", "goods", "nums", ]


class OrderInfoAdmin(object):
    list_display = ["user", "order_sn",  "trade_no", "pay_status", "post_script", "order_mount",
                    "order_mount", "pay_time", "add_time"]

    class OrderGoodsInline(object):
        model = OrderGoods
        exclude = ['add_time', ]
        extra = 1
        style = 'tab'

    inlines = [OrderGoodsInline, ]


xadmin.site.register(ShoppingCart, ShoppingCartAdmin)
xadmin.site.register(OrderInfo, OrderInfoAdmin)
# trade/apps.py

from django.apps import AppConfig


class TradeConfig(AppConfig):
    name = 'trade'
    verbose_name = '交易管理'


# trade/__init__.py

default_app_config = 'trade.apps.TradeConfig'

(4)user_operation/adminx.py

# user_operation/adminx.py


import xadmin
from .models import UserFav, UserLeavingMessage, UserAddress


class UserFavAdmin(object):
    list_display = ['user', 'goods', "add_time"]


class UserLeavingMessageAdmin(object):
    list_display = ['user', 'message_type', "message", "add_time"]


class UserAddressAdmin(object):
    list_display = ["signer_name", "signer_mobile", "district", "address"]

xadmin.site.register(UserFav, UserFavAdmin)
xadmin.site.register(UserAddress, UserAddressAdmin)
xadmin.site.register(UserLeavingMessage, UserLeavingMessageAdmin)
# user_operation/apps.py

from django.apps import AppConfig


class UserOperationConfig(AppConfig):
    name = 'user_operation'
    verbose_name = '操作管理'


# user_operation/__init__.py

default_app_config = 'user_operation.apps.UserOperationConfig'

(5)生成数据库表

python manage.py makemigrations

python manage.py migrate

4.4.导入商品类别数据

由于分类和商品很多,就写个脚本导入数据

单独使用django的model,批量导入数据

  • db_tools下新建文件夹data,然后把前端的json文件(category_data和product_data)拷贝到里面
  • 把brands和goods图片拷贝到media目录下

db_tools下新建文件 import_category_data.py

# db_tools/data/import_category_data.py

#独立使用django的model
import sys
import os

#获取当前文件的路径(运行脚本)
pwd = os.path.dirname(os.path.realpath(__file__))
#获取项目的跟目录
sys.path.append(pwd+"../")
#要想单独使用django的model,必须指定一个环境变量,会去settings配置找
#参照manage.py里面就知道为什么这样设置了
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MxShop.settings")

import django
django.setup()

from goods.models import GoodsCategory

from db_tools.data.category_data import row_data

#一级类
for lev1_cat in row_data:
    lev1_intance = GoodsCategory()
    lev1_intance.code = lev1_cat["code"]
    lev1_intance.name = lev1_cat["name"]
    lev1_intance.category_type = 1
    #保存到数据库
    lev1_intance.save()
#二级类
    for lev2_cat in lev1_cat["sub_categorys"]:
        lev2_intance = GoodsCategory()
        lev2_intance.code = lev2_cat["code"]
        lev2_intance.name = lev2_cat["name"]
        lev2_intance.category_type = 2
        lev2_intance.parent_category = lev1_intance
        lev2_intance.save()
#三级类
        for lev3_cat in lev2_cat["sub_categorys"]:
            lev3_intance = GoodsCategory()
            lev3_intance.code = lev3_cat["code"]
            lev3_intance.name = lev3_cat["name"]
            lev3_intance.category_type = 3
            lev3_intance.parent_category = lev2_intance
            lev3_intance.save()

然后运行脚本 import_category_data.py  数据就可以保存到数据库了

4.5.导入商品

在data目录下新建import_goods_data.py

import sys
import os

pwd = os.path.dirname(os.path.realpath(__file__))
sys.path.append(pwd+"../")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MxShop.settings")

import django
django.setup()

from goods.models import Goods, GoodsCategory, GoodsImage

from db_tools.data.product_data import row_data

for goods_detail in row_data:
    goods = Goods()
    goods.name = goods_detail["name"]
    #前端中是“¥232”,数据库中是float类型,所以要替换掉
    goods.market_price = float(int(goods_detail["market_price"].replace("¥", "").replace("元", "")))
    goods.shop_price = float(int(goods_detail["sale_price"].replace("¥", "").replace("元", "")))
    goods.goods_brief = goods_detail["desc"] if goods_detail["desc"] is not None else ""
    goods.goods_desc = goods_detail["goods_desc"] if goods_detail["goods_desc"] is not None else ""
    # 取第一张作为封面图
    goods.goods_front_image = goods_detail["images"][0] if goods_detail["images"] else ""
    #取最后一个
    category_name = goods_detail["categorys"][-1]
    # 取出当前子类对应的GoodsCategory对象,filter没有匹配的会返回空数组,不会抛异常。
    category = GoodsCategory.objects.filter(name=category_name)
    if category:
        goods.category = category[0]
    goods.save()

    for goods_image in goods_detail["images"]:
        goods_image_instance = GoodsImage()
        goods_image_instance.image = goods_image
        goods_image_instance.goods = goods
        goods_image_instance.save()

然后运行,把商品生产到数据库中

配置media路径

settings中

# 设置上传文件的路径
MEDIA_URL="/media/"
MEDIA_ROOT=os.path.join(BASE_DIR,"media")

urls.py

# MxShop/urls.py

from django.urls import path,include
import xadmin
from django.views.static import serve
from MxShop.settings import MEDIA_ROOT

urlpatterns = [
    path('xadmin/', xadmin.site.urls),
    path('ueditor/',include('DjangoUeditor.urls' )),
    #文件
    path('media/<path:path>',serve,{'document_root':MEDIA_ROOT}),
]

五、商品列表页

5.1.django的view实现商品列表页

(1)goods/view_base.py

在goods文件夹下面新建view_base.py,为了区分django和django rest framework的view

利用Django的view实现返回json数据

# goods/view_base.py

from django.views.generic import View
from goods.models import Goods

class GoodsListView(View):
    def get(self,request):
        #通过django的view实现商品列表页
        json_list = []
        #获取所有商品
        goods = Goods.objects.all()
        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)

        from django.http import HttpResponse
        import json
        #返回json,一定要指定类型content_type='application/json'
        return HttpResponse(json.dumps(json_list),content_type='application/json')

(2)MxShop/urls.py

from goods.view_base import GoodsListView

urlpatterns = [
   #商品列表页
    path('goods/',GoodsListView.as_view(),name='goods-list')
]

访问http://127.0.0.1:8000/goods/  可以获取商品列表信息的json数据

5.2.django的serializer序列化model

(1)model_to_dict

当字段比较多时,一个字段一个字段的提取很麻烦,可以用model_to_dict,将model整个转化为dict

# goods/view_base.py

from django.views.generic import View
from goods.models import Goods

class GoodsListView(View):
    def get(self,request):
        #通过django的view实现商品列表页
        json_list = []
        #获取所有商品
        goods = Goods.objects.all()
        # 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)

        from django.forms.models import model_to_dict
        for good in goods:
            json_dict = model_to_dict(good)
            json_list.append(json_dict)

        from django.http import HttpResponse
        import json
        #返回json,一定要指定类型content_type='application/json'
        return HttpResponse(json.dumps(json_list),content_type='application/json')

但是这样有个问题,就是ImageFieldFile 和add_time字段不能序列化

如何才能将所有字段序列化呢?就要用到django的serializers

(2)django serializer的用法

# goods/view_base.py

from django.views.generic import View
from goods.models import Goods

class GoodsListView(View):
    def get(self,request):
        #通过django的view实现商品列表页
        json_list = []
        #获取所有商品
        goods = Goods.objects.all()
        # 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)

        import json
        from django.core import serializers
        from django.http import JsonResponse

        json_data = serializers.serialize('json',goods)
        json_data = json.loads(json_data)
        #In order to allow non-dict objects to be serialized set the safe parameter to False.
        return JsonResponse(json_data,safe=False)

django的serializer虽然可以很简单实现序列化,但是有几个缺点

  • 字段序列化定死的,要想重组的话非常麻烦
  • 从上面截图可以看出来,images保存的是一个相对路径,我们还需要补全路径,而这些drf都可以帮助我们做到

以上写了这么多只是为了引入django rest framework和简单介绍django的序列化用法,下面就是重点讲解django rest framework了

5.3.APIview方式实现商品列表页

(1)安装

  • pip install coreapi                         drf的文档支持
  • pip install django-guardian           drf对象级别的权限支持

(2)配置def文档的url

MxShop/urls.py

from rest_framework.documentation import include_docs_urls

urlpatterns = [
    #drf文档,title自定义
    path('docs',include_docs_urls(title='生鲜超市')),
]

(3)配置rest_framework

settings.py中添加

INSTALLED_APPS = [
    'rest_framework',
]

MxShop/urls.py

urlpatterns = [
    path('api-auth/',include('rest_framework.urls')),
]

4)goods文件夹下面新建serializers.py

用drf的序列化实现商品列表页展示,代码如下:

# goods/serializers.py

from rest_framework import serializers


class GoodsSerializer(serializers.Serializer):
    name = serializers.CharField(required=True,max_length=100)
    click_num = serializers.IntegerField(default=0)
    goods_front_image = serializers.ImageField()

(5)goods/views.py

# googd/views.py

from rest_framework.views import APIView
from goods.serializers import GoodsSerializer
from .models import Goods
from rest_framework.response import Response


class GoodsListView(APIView):
    '''
    商品列表
    '''
    def get(self,request,format=None):
        goods = Goods.objects.all()
        goods_serialzer = GoodsSerializer(goods,many=True)
        return Response(goods_serialzer.data)

5.4.drf的Modelserializer实现商品列表页

上面是用Serializer实现的,需要自己手动添加字段,如果用Modelserializer,会更加的方便,直接用__all__就可以全部序列化

# goods/serializers.py

from rest_framework import serializers
from .models import Goods

#Serializer实现商品列表页
# class GoodsSerializer(serializers.Serializer):
#     name = serializers.CharField(required=True,max_length=100)
#     click_num = serializers.IntegerField(default=0)
#     goods_front_image = serializers.ImageField()

#ModelSerializer实现商品列表页
class GoodsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Goods
        fields = '__all__'

 category只显示分类的id,Serialzer还可以嵌套使用,覆盖外键字段

# goods/serializers.py

from rest_framework import serializers
from .models import Goods,GoodsCategory

#Serializer实现商品列表页
# class GoodsSerializer(serializers.Serializer):
#     name = serializers.CharField(required=True,max_length=100)
#     click_num = serializers.IntegerField(default=0)
#     goods_front_image = serializers.ImageField()


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


#ModelSerializer实现商品列表页
class GoodsSerializer(serializers.ModelSerializer):
    #覆盖外键字段
    category = CategorySerializer()
    class Meta:
        model = Goods
        fields = '__all__'

5.5.GenericView实现商品列表页

(1)mixins和generic一起用用

GenericAPIView继承APIView,封装了很多方法,比APIView功能更强大

用的时候需要定义queryset和serializer_class, GenericAPIView里面默认为空
  • queryset = None
  • serializer_class = None

ListModelMixin里面list方法帮我们做好了分页和序列化的工作,只要调用就好了

class ListModelMixin(object):
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

ListModelMixin源码

实现如下:

from goods.serializers import GoodsSerializer
from .models import Goods
from rest_framework.response import Response
from rest_framework import mixins
from rest_framework import generics


class GoodsListView(mixins.ListModelMixin,generics.GenericAPIView):
    '商品列表页'
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer

    def get(self,request,*args,**kwargs):
        return self.list(request,*args,**kwargs)

上面的代码优化,可以直接继承ListAPIView,ListAPIView主要做了两件事:

  • ListAPIView(mixins.ListModelMixin,GenericAPIView)        继承了这两个类
  • 写好了get方法

我们要获取商品列表页的信息,只要写三行代码就可以了

class GoodsListView(generics.ListAPIView):
    '商品列表页'
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer

5.6.添加分页功能

先看rest_framework/settings.py源码,里面可以找到如何配置:比如认证、权限和分页等等

 添加分页功能,配置如下:

REST_FRAMEWORK = {
    #分页
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    #每页显示的个数
    'PAGE_SIZE': 10,
}

自定义分页功能

from rest_framework.pagination import PageNumberPagination

class GoodsPagination(PageNumberPagination):
    '''
    商品列表自定义分页
    '''
    #默认每页显示的个数
    page_size = 10
    #可以动态改变每页显示的个数
    page_size_query_param = 'page_size'
    #页码参数
    page_query_param = 'page'
    #最多能显示多少页
    max_page_size = 100


class GoodsListView(generics.ListAPIView):
    '商品列表页'

    pagination_class = GoodsPagination    #分页
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer

settings.py里面就不用设置了

5.7.viewsets和router完成商品列表页

主要用到viewsets中的GenericViewSet

ViewSets和Routers结合使用

MxShop/yrls.py

from goods.views import GoodsListViewSet
from rest_framework.routers import DefaultRouter

router = DefaultRouter()

#配置goods的url
router.register(r'goods', GoodsListViewSet)

urlpatterns = [
    #商品列表页
    re_path('^', include(router.urls)),
]

views.py

必须定义一个默认的排序方式

class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
    '商品列表页'

    # 分页
    pagination_class = GoodsPagination
    #这里必须要定义一个默认的排序,否则会报错
    queryset = Goods.objects.all().order_by('id')
    serializer_class = GoodsSerializer

5.8.drf的APIView、GenericView、viewsets和router的原理分析

genericViewSet 是最高的一层

往下

GenericViewSet(viewsets)     ----drf

  GenericAPIView                  ---drf

    APIView                        ---drf

      View            ----django

这些view功能的不同,主要的是有mixin的存在

mixins总共有五种:

  CreateModelMixin   ListModelMixin   UpdateModelMixin    RetrieveModelMixin    DestoryModelMixin

"""
Basic building blocks for generic class based views.

We don't bind behaviour to http method handlers yet,
which allows mixin classes to be composed in interesting ways.
"""
from __future__ import unicode_literals

from rest_framework import status
from rest_framework.response import Response
from rest_framework.settings import api_settings


class CreateModelMixin(object):
    """
    Create a model instance.
    """
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def perform_create(self, serializer):
        serializer.save()

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}


class ListModelMixin(object):
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)


class RetrieveModelMixin(object):
    """
    Retrieve a model instance.
    """
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)


class UpdateModelMixin(object):
    """
    Update a model instance.
    """
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response(serializer.data)

    def perform_update(self, serializer):
        serializer.save()

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)


class DestroyModelMixin(object):
    """
    Destroy a model instance.
    """
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        instance.delete()

mixins.py源码

以ListModelMixin为例:

如果不继承ListModelMixin的话,就无法将get和商品的列表关联起来,另外还有其中的分页等等,都无法实现。

还有其它几个mixin(增删改查局部),这些功能都是mixin做的,我们一般都是用viewsets

ViewSet类与View类其实几乎是相同的,但提供的是read或update这些操作,而不是get或put 等HTTP动作。同时,ViewSet为我们提供了默认的URL结构, 使得我们能更专注于API本身。

 Router提供了一种简单,快速,集成的方式来定义一系列的urls

 5.9.drf的request和response介绍

REST framework 的 Request 类扩展与标准的 HttpRequest,并做了相应的增强,比如更加灵活的请求解析(request parsing)和认证(request authentication)。

Request 解析

REST framwork 的 Request 对象提供了灵活的请求解析,允许你使用 JSON data 或 其他 media types 像通常处理表单数据一样处理请求。

.data

request.data 返回请求主题的解析内容。这跟标准的 request.POST 和 request.FILES 类似,并且还具有以下特点:

  • 包括所有解析的内容,文件(file) 和 非文件(non-file inputs)。
  • 支持解析 POST 以外的 HTTP method , 比如 PUT, PATCH
  • 更加灵活,不仅仅支持表单数据,传入同样的 JSON 数据一样可以正确解析,并且不用做额外的处理(意思是前端不管提交的是表单数据,还是 JSON 数据,.data 都能够正确解析)。

.data 具体操作,以后再说~

.query_params

request.query_params 等同于 request.GET,不过其名字更加容易理解。

为了代码更加清晰可读,推荐使用 request.query_params ,而不是 Django 中的 request.GET,这样那够让你的代码更加明显的体现出 ----- 任何 HTTP method 类型都可能包含查询参数(query parameters),而不仅仅只是 'GET' 请求。

.parser

APIView 类或者 @api_view 装饰器将根据视图上设置的 parser_classes 或 settings 文件中的 DEFAULT_PARSER_CLASSES 设置来确保此属性(.parsers)自动设置为 Parser 实例列表。

如果你非要看看它里面是什么,可以打印出来看看,大概长这样:

[<rest_framework.parsers.JSONParser object at 0x7fa850202d68>, <rest_framework.parsers.FormParser object at 0x7fa850202be0>, <rest_framework.parsers.MultiPartParser object at 0x7fa850202860>]

包含三个解析器 JSONParserFormParserMultiPartParser

注意: 如果客户端发送格式错误的内容,则访问 request.data 可能会引发 ParseError 。默认情况下, REST framework 的 APIView 类或者 @api_view 装饰器将捕获错误并返回 400 Bad Request 响应。 如果客户端发送的请求内容无法解析(不同于格式错误),则会引发 UnsupportedMediaType 异常,默认情况下会被捕获并返回 415 Unsupported Media Type 响应。

Responses

与基本的 HttpResponse 对象不同,TemplateResponse 对象保留了视图提供的用于计算响应的上下文的详细信息。直到需要时才会计算最终的响应输出,也就是在后面的响应过程中进行计算。 — Django 文档

REST framework 通过提供一个 Response 类来支持 HTTP 内容协商,该类允许你根据客户端请求返回不同的表现形式(如: JSON ,HTML 等)。

Response 类的子类是 Django 的 SimpleTemplateResponseResponse 对象使用数据进行初始化,数据应由 Python 对象(native Python primitives)组成。然后 REST framework 使用标准的 HTTP 内容协商来确定它应该如何渲染最终响应的内容。

当然,您也可以不使用 Response 类,直接返回常规 HttpResponse 或 StreamingHttpResponse 对象。 使用 Response 类只是提供了一个更好的交互方式,它可以返回多种格式。

除非由于某种原因需要大幅度定制 REST framework ,否则应该始终对返回 Response 对象的视图使用 APIView 类或 @api_view 装饰器。这样做可以确保视图执行内容协商,并在视图返回之前为响应选择适当的渲染器。

创建 response

Response()

与普通 HttpResponse 对象不同,您不会使用渲染的内容实例化 Response 对象。相反,您传递的是未渲染的数据,可能包含任何 Python 对象。

由于 Response 类使用的渲染器不能处理复杂的数据类型(比如 Django 的模型实例),所以需要在创建 Response 对象之前将数据序列化为基本的数据类型。

你可以使用 REST framework 的 Serializer 类来执行序列化的操作,也可以用自己的方式来序列化。

构造方法: Response(data, status=None, template_name=None, headers=None, content_type=None)

参数:

  • data: 响应的序列化数据。
  • status: 响应的状态代码。默认为200。
  • template_name: 选择 HTMLRenderer 时使用的模板名称。
  • headers: 设置 HTTP header,字典类型。
  • content_type: 响应的内容类型,通常渲染器会根据内容协商的结果自动设置,但有些时候需要手动指定。

属性

.data

还没有渲染,但已经序列化的响应数据。

.status_code

状态码

.content

将会返回的响应内容,必须先调用 .render() 方法,才能访问 .content 。

.template_name

只有在 response 的渲染器是 HTMLRenderer 或其他自定义模板渲染器时才需要提供。

.accepted_renderer

用于将会返回的响应内容的渲染器实例。

从视图返回响应之前由 APIView 或 @api_view 自动设置。

.accepted_media_type

内容协商阶段选择的媒体类型。

从视图返回响应之前由 APIView 或 @api_view 自动设置。

.renderer_context

将传递给渲染器的 .render() 方法的附加的上下文信息字典。

从视图返回响应之前由 APIView 或 @api_view 自动设置。

标准 HttpResponse 属性

Response 类扩展于 SimpleTemplateResponse,并且响应中也提供了所有常用的属性和方法。例如,您可以用标准方式在响应中设置 header

response = Response()
response['Cache-Control'] = 'no-cache'

.render()

与其他任何 TemplateResponse 一样,调用此方法将响应的序列化数据呈现为最终响应内容。响应内容将设置为在 accepted_renderer 实例上调用 .render(data,accepted_media_type,renderer_context) 方法的结果。

通常不需要自己调用 .render() ,因为它是由 Django 处理的。

5.10.drf的过滤

drf的filter用法   http://www.django-rest-framework.org/api-guide/filtering/

(1)添加到app里面

INSTALLED_APPS = [
     'django_filters',
]

(2)新建filter.py

自定义一个过滤器

# goods/filters.py

import django_filters

from .models import Goods


class GoodsFilter(django_filters.rest_framework.FilterSet):
    '''
    商品过滤的类
    '''
    #两个参数,name是要过滤的字段,lookup是执行的行为,‘小与等于本店价格’
    price_min = django_filters.NumberFilter(name="shop_price", lookup_expr='gte')
    price_max = django_filters.NumberFilter(name="shop_price", lookup_expr='lte')

    class Meta:
        model = Goods
        fields = ['price_min', 'price_max']

(3)views.py

from .filters import GoodsFilter
from django_filters.rest_framework import DjangoFilterBackend

class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
    '商品列表页'

    #这里必须要定义一个默认的排序,否则会报错
    queryset = Goods.objects.all().order_by('id')
    # 分页
    pagination_class = GoodsPagination
    serializer_class = GoodsSerializer
    filter_backends = (DjangoFilterBackend,)

    # 设置filter的类为我们自定义的类
    filter_class = GoodsFilter

5.11.drf的搜索和排序


添加搜索功能

搜索的字段可以使用正则表达式,更加的灵活

class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
    '商品列表页'

    # 这里必须要定义一个默认的排序,否则会报错
    queryset = Goods.objects.all().order_by('id')
    # 分页
    pagination_class = GoodsPagination
    serializer_class = GoodsSerializer
    filter_backends = (DjangoFilterBackend,filters.SearchFilter)

    # 设置filter的类为我们自定义的类
    filter_class = GoodsFilter
    #搜索,=name表示精确搜索,也可以使用各种正则表达式
    search_fields = ('=name','goods_brief')

添加排序功能

class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
    '商品列表页'

    #这里必须要定义一个默认的排序,否则会报错
    queryset = Goods.objects.all()
    # 分页
    pagination_class = GoodsPagination
    #序列化
    serializer_class = GoodsSerializer
    filter_backends = (DjangoFilterBackend,filters.SearchFilter,filters.OrderingFilter)

    # 设置filter的类为我们自定义的类
    #过滤
    filter_class = GoodsFilter
    #搜索,=name表示精确搜索,也可以使用各种正则表达式
    search_fields = ('=name','goods_brief')
    #排序
    ordering_fields = ('sold_num', 'add_time')

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值