Django--005 DRF-View

1. View

1.2 简介

  • Django默认的视图基类,引用方式:from django.views import View
  • 视图views.py有两种写法,基于类或基于函数

1.1 requests对象

  • request.META:获取一个标准的python字典,它包含了所有的HTTP请求信息
  • request.scheme:请求的方式,http或https
  • request.path:请求路径
  • request.session:获取的是一个类似于字典的对象,可以进行读取写入操作
  • request.method:请求方式 POST/GET
  • request.body:获取请求数据,常见用法json.loads(request.body.decode(‘utf-8’), encoding=‘utf-8’)

1.2 代码

import json
from django.http import JsonResponse, Http404
from django.views import View
from projects.models import Projects
from projects.serializers import ProjectsModelSerializers
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status


class ProjectList(View):
    """"
    类视图
    """

    def get(self, request):
        qs = Projects.objects.all()
        # many=True: 输出querySet,返回多条数据
        serializer = ProjectsModelSerializers(instance=qs, many=True)
        return JsonResponse(serializer.data, safe=False, status=200)

    def post(self, request):
        """
        httpie模拟请求:http POST :8000/projects/ name='项目009' leader="zz" developer='李四'  tester='张三' \
                                      app_name='测试应用'  desc='demo desc'
        """
        # 1. 前端传入json数据转为python_data
        data = json.loads(request.body.decode('utf-8'), encoding='utf-8')
        # 2. 数据校验
        serializer = ProjectsModelSerializers(data=data)
        try:
            # 设置raise_exception=True后serializer.errors可以获取到报错信息
            serializer.is_valid(raise_exception=True)
        except Exception as e:
            # 3. 校验失败则返回异常dict
            return JsonResponse(serializer.errors)
        # 3. 校验通过则调用序列化器的save方法(会调用序列化器的create方法)新建数据
        serializer.save()
        # 返回新建成功的这条数据
        return JsonResponse(serializer.data, safe=False, status=201)

2. APIView

2.1 与View对比

  • APIView继承自Django的View,使用时视图需要继承APiView
  • 传入到视图的是Request对象而不是Django的HttpRequest对象
  • 视图方法可以返回Response对象,会把响应数据处理(render)为符合前段要求的格式,取决于accept这个参数
  • 任何APIException异常都会被捕获到,并且处理成合适的响应信息
  • 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制

2.2 view代码

# view.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from projects.models import Projects
from projects.serializer import ProjectModelSerializer

# 继承自APIView
class ProjectList(APIView):
    """"
    类视图
    """
    def get(self, request):
        projects = Projects.objects.all()
        serializer = ProjectModelSerializer(instance=projects, many=True)
		# 返回Response对象
        return Response(serializer.data, status=status.HTTP_200_OK)

    def post(self, request):
        """
        httpie json格式请求模拟:http POST :8000/projects/ name='项目009' leader="zz" developer='李四' tester='王五' app_name='测试应用' desc='demo desc'
        httpie form-data格式请求模拟:http -f POST :8000/projects/ name='项目009' leader="zz" developer='李四' tester='王五' app_name='测试应用' app_version='1.0' desc='demo desc'
        """
        serializer = ProjectModelSerializer(data=request.data)
        try:
            serializer.is_valid(raise_exception=True)
        except Exception as e:
            return Response(serializer.errors)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)

3. GenericAPIView

3.1 简介

  • 继承关系: rest_framework.generics.GenericAPIView—>rest_framework.views.APIView—>django.views.generic.base.View—>obiect—>typing.hashable
  • 必须指定的属性: queryset、serializer_class
    视图类继承自GenericAPIView后进行排序

3.2 对比

项目ViewAPIViewGenericAPIView
继承自ObjectViewAPIView
params获取request.GETrequest.query_paramsrequest.query_params
json获取request.bodyrequest.datarequest.data
data获取request.POSTrequest.datarequest.data
file获取request.FILESrequest.datarequest.data
returnJsonResponseResponserequest.data

4. GenericAPIView之过滤分页排序

4.1 过滤

  • 库安装
pip install django-filter
  • 注册app
INSTALLED_APPS = [
	...
    # 注册DRF子应用
    'rest_framework',
    'django_filters',
]
  • 引擎和字段配置
  • 引擎配置有类视图和全局seetings.py两种
  • 代码
# view.py
from projects.models import Projects
from projects.serializers import ProjectsModelSerializers
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework import status


# 1. 需要继承自GenericAPIView
class ProjectList(GenericAPIView):
    # 2.指定查询集
    queryset = Projects.objects.all()
    # 3. 指定序列化器类
    serializer_class = ProjectsModelSerializers
    # 4. 指定过滤引擎
    filter_backends = [DjangoFilterBackend]
    # 5. 指定过滤字段
    filterset_fields = ['id', 'name', 'leader']

    def get(self, request):
        """
        http://127.0.0.1:8000/projects/?id=6&name=项目5&leader=风清扬
        """
        # 动态获取查询集
        qs = self.get_queryset()
        # 过滤查询集
        qs = self.filter_queryset(qs)
        # 序列化
        serializer = self.get_serializer(instance=qs, many=True)
        # 返回列表
        return Response(serializer.data, status=status.HTTP_200_OK)

4.2 排序

  • 代码
# view.py
from django_filters.rest_framework import DjangoFilterBackend
from projects.models import Projects
from projects.serializers import ProjectsModelSerializers
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework import status, filters


# 1. 需要继承自GenericAPIView
class ProjectList(GenericAPIView):
    # 2.指定查询集
    queryset = Projects.objects.all()
    # 3. 指定序列化器类
    serializer_class = ProjectsModelSerializers
    # 4. 指定过滤排序引擎
    filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
    # 5. 指定过滤字段
    filterset_fields = ['id', 'name', 'leader']
    # 6. 指定排序字段
    ordering_fields = ['id', 'name', 'leader']

    def get(self, request):
        """
        倒序:http://127.0.0.1:8000/projects/?ordering=-id
        """
        # 动态获取查询集
        qs = self.get_queryset()
        # 过滤查询集
        qs = self.filter_queryset(qs)
        # 序列化
        serializer = self.get_serializer(instance=qs, many=True)
        # 返回列表
        return Response(serializer.data, status=status.HTTP_200_OK)

4.3 分页

  • 约束
  • 必须指定分页引擎,可以在类视图中,也可以在全局settings.py中指定
  • 必须指定PAGE_SIZE
  • 代码
from django_filters.rest_framework import DjangoFilterBackend
from projects.models import Projects
from projects.serializers import ProjectsModelSerializers
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework import status, filters
from rest_framework.pagination import PageNumberPagination


# 重写分页器类,也可配置在settings.py中
# page_size必须重写
class PageNumberPaginationManual(PageNumberPagination):
    page_query_param = 'page_num'
    page_size_query_param = 'page_size'
    page_size = 2
    max_page_size = 50
    page_query_description = '第几页'
    page_size_query_description = '每页几条'


# 1. 需要继承自GenericAPIView
class ProjectList(GenericAPIView):
    # 2.指定查询集
    queryset = Projects.objects.all()
    # 3. 指定序列化器类
    serializer_class = ProjectsModelSerializers
    # # 4. 指定过滤、排序引擎
    # filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
    # # 5. 指定过滤字段
    # filterset_fields = ['id', 'name', 'leader']
    # # 6. 指定排序字段
    # ordering_fields = ['id', 'name', 'leader']
    # 7. 定义分页类
    pagination_class = PageNumberPaginationManual

    def get(self, request):
        """
        分页:http://127.0.0.1:8000/projects/?page_num=3&page_size=3
        """
        # 过滤查询集
        qs = self.filter_queryset(self.get_queryset())
        # 获取分页后的查询集
        page = self.paginate_queryset(qs)
        if page is not None:
            # 序列化
            serializer = self.get_serializer(instance=page, many=True)
            # 如果存在分页,则返回分页的值
            return self.get_paginated_response(serializer.data)
        serializer = self.get_serializer(instance=qs, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

4.4 代码

  • settings.py全局配置
# settings.py

# 2. 添加'django_filters'子应用
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 注册子应用
    'rest_framework',
    'django_filters',
    'interfaces.apps.InterfaceConfig',
    'projects.apps.ProjectConfig'
]

# DRF配置信息
REST_FRAMEWORK = {
    # 默认响应渲染类
    'DEFAULT_RENDERER_CLASSES': (
        # json渲染器为第一优先级
        'rest_framework.renderers.JSONRenderer',
        # 可浏览的API渲染器为第二优先级
        'rest_framework.renderers.BrowsableAPIRenderer',
    ),
    # 过滤和排序引擎配置
    'DEFAULT_FILTER_BACKENDS': ['rest_framework.filters.OrderingFilter',
                                'django_filters.rest_framework.backends.DjangoFilterBackend']
    # 默认分页引擎
    # 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'DEFAULT_PAGINATION_CLASS': 'utils.pagination.PageNumberPaginationManual',
    # --设置每页展示条数
    'PAGE_SIZE': 3

}

  • 自定义分页器
# utils.pagination.py

from rest_framework.pagination import PageNumberPagination


class PageNumberPaginationManual(PageNumberPagination):
    page_query_param = 'page_num'
    page_size_query_param = 'page_size'
    # 类中page_size配置优先于settings中全局配置
    page_size = 10
    max_page_size = 50
# -*-coding:utf-8 -*-
# views.py

from projects.models import Projects
from projects.serializers import ProjectsModelSerializers
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework import status, filters


# 1. 需要继承自GenericAPIView
class ProjectList(GenericAPIView):
    # 2.指定查询集
    queryset = Projects.objects.all()
    # 3. 指定序列化器类
    serializer_class = ProjectsModelSerializers
    # # 4. 指定过滤、排序引擎
    # filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
    # 5. 指定过滤字段
    filterset_fields = ['id', 'name', 'leader']
    # 6. 指定排序字段
    ordering_fields = ['id', 'name', 'leader']
    # 7. 定义分页类
    # pagination_class = PageNumberPaginationManual

    def get(self, request):
        """
        过滤:http://127.0.0.1:8000/projects/?id=6&name=项目5&leader=风清扬
        倒序:http://127.0.0.1:8000/projects/?ordering=-id
        分页:http://127.0.0.1:8000/projects/?ordering=name&page_num=3&page_size=3
        """
        # 过滤查询集
        qs = self.filter_queryset(self.get_queryset())
        # 获取分页后的查询集
        page = self.paginate_queryset(qs)
        if page is not None:
            # 序列化
            serializer = self.get_serializer(instance=page, many=True)
            # 如果存在分页,则返回分页的值
            return self.get_paginated_response(serializer.data)
        serializer = self.get_serializer(instance=qs, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

    def post(self, request):
        """
        httpie模拟请求:http POST :8000/projects/ name='项目009' leader="zz" developer='李四'  tester='张三' \
                                      app_name='测试应用'  desc='demo desc'
        """
        # 2. 数据校验
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 返回新建成功的这条数据
        return Response(serializer.data, status=status.HTTP_201_CREATED)


class ProjectDetail(GenericAPIView):
    """
    模型类继承自GenericAPIView后,无需定义get_object方法
    """
    # 2.指定查询集
    queryset = Projects.objects.all()
    # 3. 指定序列化器类
    serializer_class = ProjectsModelSerializers
    # 默认参数为pk,可以自定义
    lookup_field = 'id'

    def get(self, request, id):
        """
        httpie模拟请求:http  :8000/projects/12
        """
        qs = self.get_object()
        serializer = ProjectsModelSerializers(instance=qs)
        return Response(serializer.data, status=status.HTTP_200_OK)

    def put(self, request, id):
        """
        httpie模拟请求:http PUT :8000/projects/12 name='项目0091' leader="张三" developer='李四' \
                                tester='王五' app_name='测试应用' desc='demo desc'
        """
        # 1.判断数据是否存在
        qs = self.get_object()
        # 2. 同时存在反序列化和序列化时,同时传参会调用序列化器update方法
        serializer = self.get_serializer(instance=qs, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def delete(self, request, id):
        """
        httpie模拟请求:http DELETE :8000/projects/12
        """
        # 1. 判断数据是否存在
        qs = self.get_object()
        # 2. 删除
        qs.delete()
        return Response(None, status=status.HTTP_204_NO_CONTENT)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 安装Elasticsearch和Python Elasticsearch客户端 - Elasticsearch安装可以参考官网的[安装文档](https://www.elastic.co/guide/en/elasticsearch/reference/current/install-elasticsearch.html) - Python Elasticsearch客户端可以使用pip安装:`pip install elasticsearch` 2. 在Django项目中创建一个app,用于处理与Elasticsearch相关的逻辑。 3. 配置Elasticsearch连接信息,可以在Django的`settings.py`中添加以下配置: ``` ELASTICSEARCH_DSL = { 'default': { 'hosts': 'localhost:9200' }, } ``` 其中,`hosts`就是Elasticsearch的地址,这里使用默认的`localhost:9200`。 4. 创建Elasticsearch索引模板,可以在app目录下创建一个`search_indexes.py`文件,定义索引模板: ``` from elasticsearch_dsl import Document, Text, Date, Keyword class ArticleIndex(Document): title = Text() content = Text() pub_date = Date() tags = Keyword(multi=True) class Index: name = 'articles' ``` 其中,`ArticleIndex`是一个继承自`Document`的类,定义了索引的字段和类型。`Index`类中的`name`属性指定了索引的名称。 5. 在app目录下创建`serializers.py`文件,定义序列化器,将模型序列化为Elasticsearch索引模板: ``` from rest_framework import serializers from .models import Article from .search_indexes import ArticleIndex class ArticleIndexSerializer(serializers.ModelSerializer): class Meta: model = Article fields = ('id', 'title', 'content', 'pub_date', 'tags') def save(self, **kwargs): article = super().save(**kwargs) article_index = ArticleIndex(meta={'id': article.id}, **article.__dict__) article_index.save() return article ``` 其中,`ArticleIndexSerializer`继承自`ModelSerializer`,定义了序列化的模型和字段。在`save`方法中,先保存模型,再将模型数据序列化为Elasticsearch索引模板,最后保存到Elasticsearch中。 6. 在app目录下创建`views.py`文件,定义视图函数,实现Elasticsearch搜索功能: ``` from rest_framework.views import APIView from rest_framework.response import Response from elasticsearch_dsl import Q from .search_indexes import ArticleIndex from .serializers import ArticleIndexSerializer class ArticleSearchView(APIView): def get(self, request): query = request.query_params.get('q', '') s = ArticleIndex.search().query( Q('multi_match', query=query, fields=['title', 'content', 'tags']) ) response = [] for hit in s.execute().hits: serializer = ArticleIndexSerializer(data=hit.to_dict()) serializer.is_valid() response.append(serializer.data) return Response(response) ``` 其中,`ArticleSearchView`继承自`APIView`,定义了一个`get`方法,接收`q`参数作为搜索关键词。通过Elasticsearch DSL构建查询语句,搜索索引模板中的数据,最后将搜索结果序列化返回。 7. 在app目录下创建`urls.py`文件,定义路由: ``` from django.urls import path from .views import ArticleSearchView urlpatterns = [ path('search/', ArticleSearchView.as_view(), name='article_search'), ] ``` 其中,`search`路由对应了`ArticleSearchView`视图函数。 8. 在Django的`settings.py`中添加app,配置数据库信息: ``` INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'app_name', # 添加app ] DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'db_name', 'USER': 'db_user', 'PASSWORD': 'db_password', 'HOST': 'localhost', 'PORT': '3306', } } ``` 9. 在app目录下创建`models.py`文件,定义模型,使用Django ORM作为数据源: ``` from django.db import models class Article(models.Model): title = models.CharField(max_length=255) content = models.TextField() pub_date = models.DateTimeField(auto_now_add=True) tags = models.CharField(max_length=255, blank=True) def __str__(self): return self.title ``` 其中,`Article`是一个继承自`models.Model`的类,定义了文章的属性。 10. 在app目录下创建`admin.py`文件,注册模型到Django Admin中: ``` from django.contrib import admin from .models import Article admin.site.register(Article) ``` 11. 在Django的`urls.py`中添加app的路由: ``` from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('api/', include('app_name.urls')), ] ``` 12. 启动Django开发服务器,访问`http://localhost:8000/admin/`,进入Django Admin,创建一些文章数据。 13. 访问`http://localhost:8000/api/search/?q=django`,可以看到搜索结果,其中包含关键词`django`的文章数据。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值