Django下的 REST framework
Django REST framework 框架是一个用于构建Web API 的强大而又灵活的工具。
通常简称为DRF框架 或 REST framework。
DRF框架是建立在Django框架基础之上,由Tom Christie大牛二次开发的开源项目。
特点
- 提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化;
- 提供了丰富的类视图、Mixin扩展类,简化视图的编写;
- 丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要;
- 多种身份认证和权限认证方式的支持;
- 内置了限流系统;
- 直观的 API web 界面;
- 可扩展性,插件丰富
目前支持的python、django版本:
- Python (2.7, 3.2, 3.3, 3.4, 3.5, 3.6)
- Django (1.10, 1.11, 2.0)
1)安装drf依赖包
coreapi (1.32.0+) - Schema generation support. Markdown (2.1.0+) - Markdown support for the browsable API. # 已安装 django-filter (1.0.1+) - Filtering support. # 已安装 django-crispy-forms - Improved HTML display for filtering. # 已安装 django-guardian (1.1.1+) - Object level permissions support.
2)Mxshop下setting中注册:
rest_framework
crispy_forms
INSTALLED_APPS = [ 'django.contrib.auth', 'django.contrib.admin', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'apps.users.apps.UsersConfig', 'apps.goods.apps.GoodsConfig', 'apps.trade.apps.TradeConfig', 'apps.user_operation.apps.UserOperationConfig', 'xadmin', 'crispy_forms', 'DjangoUeditor', 'rest_framework', ]
3)配置drf文档的url
首先,导入drf中的include_docs_urls
from rest_framework.documentation import include_docs_urls
# 自动化文档,1.11版本中注意此处前往不要加$符号 path('docs/', include_docs_urls(title='生鲜电商')), # 调试登录 path('api-auth/', include('rest_framework.urls')),
1、rest_framework下的serializers,类似django下的form组件:serializers.Serializer (django下 form.Form)
REST framework首测:rest framework中的serializers组件
1)goods文件夹下面新建serializers.py,类似django中的form组件
用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()
2)goods/views.py:get方法
# 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): ''' 商品列表 '''
# get方法,获取数据,客户端输入网址时触发 def get(self,request,format=None): goods = Goods.objects.all() goods_serialzer = GoodsSerializer(goods,many=True) return Response(goods_serialzer.data)
3)Mxshop/urls.py配置:
from goods.views import GoodsListView urlpatterns = [ # 商品列表页 path('goods/', GoodsListView.as_view(),name="goods_list"), ]
浏览器输入网址:http://127.0.0.1:8000/goods/
页面效果: 关于路径相关,会自动补全路径
注:右上角log in ,可用admin超级用户登录
2)serializers的post方法,goods/views.py的GoodsListView添加post方法,客户端提交数据时会触发:
# googd/views.py from rest_framework.views import APIView from goods.serializers import GoodsSerializer from .models import Goods from rest_framework.response import Response from rest_framework import status class GoodsListView(APIView): ''' 商品列表 ''' # get方法,获取数据,客户端输入网址回车时触发 def get(self,request,format=None): goods = Goods.objects.all() goods_serialzer = GoodsSerializer(goods,many=True) return Response(goods_serialzer.data) # post方法,客户端输入数据提交时触发 def post(self,request,format=None): serializer = GoodsSerializer(data = request.data) # 将用户输入数据传入到GoodsSerializers中,类似django中form的post方法 if serializer.is_valid(): # 判断数据是否一致,没错误 serializer.save() # 保存 return Response(serializer.data,status=status.HTTP_201_CREATED) return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
goods/serializers.py中添加create方法,goods/views.py中的GoodsListView触发post函数时,调用GoodsSerializer中的create方法
from rest_framework import serializers from goods.models import Goods class GoodsSerializer(serializers.Serializer): name = serializers.CharField(required=True,max_length=100) click_num = serializers.IntegerField(default=0) goods_front_image = serializers.ImageField() def create(self,validated_data): # 保存数据到数据库 return Goods.object.create(**validated_data)
2、rest_framework下的serializers,类似django下的form组件:serializers.ModelSerializer (django下 form.ModelForm)
ModelSerializer中,不需要自己添加字段(Serializers中需要手动添加model中的字段),因为ModelSerializer会自动到相应的model模块中找对应所需字段
另外,关于外键,不做任何处理,外键字段会自动显示关联表的id,如需显示关联表所有,则需做处理:
GoodsSerializer嵌套CategorySerializer
# 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() # Category的CategorySerializer class CategorySerializer(serializers.ModelSerializer): class Meta: model = GoodsCategory fields = "__all__" #ModelSerializer实现商品列表页 #Goods类的GoodsSerializer class GoodsSerializer(serializers.ModelSerializer): #手动添加字段,如model中有则会覆盖字段。 #此为外键字段,实例化,会获取关联表的所有数据 category = CategorySerializer() class Meta: model = Goods fields = '__all__'
页面效果:
GenericView实现商品列表页
1、generics.py
GenericAPIView继承view.APIView,封装了很多方法,比APIView功能更强大
class GenericAPIView(views.APIView): """ Base class for all other generic views. """ # You'll need to either set these attributes, # or override `get_queryset()`/`get_serializer_class()`. # If you are overriding a view method, it is important that you call # `get_queryset()` instead of accessing the `queryset` property directly, # as `queryset` will get evaluated only once, and those results are cached # for all subsequent requests. queryset = None serializer_class = None # If you want to use object lookups other than pk, set 'lookup_field'. # For more complex lookup requirements override `get_object()`. lookup_field = 'pk' lookup_url_kwarg = None # The filter backend classes to use for queryset filtering filter_backends = api_settings.DEFAULT_FILTER_BACKENDS # The style to use for queryset pagination. pagination_class = api_settings.DEFAULT_PAGINATION_CLASS def get_queryset(self): """ Get the list of items for this view. This must be an iterable, and may be a queryset. Defaults to using `self.queryset`. This method should always be used rather than accessing `self.queryset` directly, as `self.queryset` gets evaluated only once, and those results are cached for all subsequent requests. You may want to override this if you need to provide different querysets depending on the incoming request. (Eg. return a list of items that is specific to the user) """ assert self.queryset is not None, ( "'%s' should either include a `queryset` attribute, " "or override the `get_queryset()` method." % self.__class__.__name__ ) queryset = self.queryset if isinstance(queryset, QuerySet): # Ensure queryset is re-evaluated on each request. queryset = queryset.all() return queryset def get_object(self): """ Returns the object the view is displaying. You may want to override this if you need to provide non-standard queryset lookups. Eg if objects are referenced using multiple keyword arguments in the url conf. """ queryset = self.filter_queryset(self.get_queryset()) # Perform the lookup filtering. lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field assert lookup_url_kwarg in self.kwargs, ( 'Expected view %s to be called with a URL keyword argument ' 'named "%s". Fix your URL conf, or set the `.lookup_field` ' 'attribute on the view correctly.' % (self.__class__.__name__, lookup_url_kwarg) ) filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]} obj = get_object_or_404(queryset, **filter_kwargs) # May raise a permission denied self.check_object_permissions(self.request, obj) return obj def get_serializer(self, *args, **kwargs): """ Return the serializer instance that should be used for validating and deserializing input, and for serializing output. """ serializer_class = self.get_serializer_class() kwargs['context'] = self.get_serializer_context() return serializer_class(*args, **kwargs) def get_serializer_class(self): """ Return the class to use for the serializer. Defaults to using `self.serializer_class`. You may want to override this if you need to provide different serializations depending on the incoming request. (Eg. admins get full serialization, others get basic serialization) """ assert self.serializer_class is not None, ( "'%s' should either include a `serializer_class` attribute, " "or override the `get_serializer_class()` method." % self.__class__.__name__ ) return self.serializer_class def get_serializer_context(self): """ Extra context provided to the serializer class. """ return { 'request': self.request, 'format': self.format_kwarg, 'view': self } def filter_queryset(self, queryset): """ Given a queryset, filter it with whichever filter backend is in use. You are unlikely to want to override this method, although you may need to call it either from a list view, or from a custom `get_object` method if you want to apply the configured filtering backend to the default queryset. """ for backend in list(self.filter_backends): queryset = backend().filter_queryset(self.request, queryset, self) return queryset @property def paginator(self): """ The paginator instance associated with the view, or `None`. """ if not hasattr(self, '_paginator'): if self.pagination_class is None: self._paginator = None else: self._paginator = self.pagination_class() return self._paginator def paginate_queryset(self, queryset): """ Return a single page of results, or `None` if pagination is disabled. """ if self.paginator is None: return None return self.paginator.paginate_queryset(queryset, self.request, view=self) def get_paginated_response(self, data): """ Return a paginated style `Response` object for the given output data. """ assert self.paginator is not None return self.paginator.get_paginated_response(data) 复制代码 用的时候需要定义queryset和serializer_class GenericAPIView里面默认为空 queryset = None serializer_class = None ListModelMixin里面list方法帮我们做好了分页和序列化的工作,只要调用就好了 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)