drf-视图组件

【一】两个视图基类(APIView和GenericAPIView)

【1】基于APIView+序列化类+Response写5个接口

  • 路由

from django.urls import path
from .views import BookView, BookDetailView
​
urlpatterns = [
    path('books/', BookView.as_view()),
    path('books/<int:pk>/', BookDetailView.as_view()),
]
  • 视图类

from rest_framework.response import Response
from rest_framework.views import APIView
​
from .models import Book
from .serializer import BookSerializer
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
​
​
class BookView(APIView):
    # 在视图类上,配置---》只运行json格式
    parser_classes = [JSONParser]
    renderer_classes = [JSONRenderer]
​
    def post(self, request):
        serializer = BookSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response({"code": 200, "msg": "添加成功", "result": serializer.data})
​
    def get(self, request):
        books = Book.objects.all()
        serializer = BookSerializer(instance=books, many=True)
        return Response({"code": 200, "msg": "查看成功", "result": serializer.data})
​
​
class BookDetailView(APIView):
    # 在视图类上,配置---》只运行json格式
    parser_classes = [JSONParser]
    renderer_classes = [JSONRenderer]
​
    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        serializer = BookSerializer(instance=book, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response({"code": 200, "msg": "修改成功", "result": serializer.data})
​
    def get(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        serializer = BookSerializer(instance=book)
        return Response({"code": 200, "msg": "查看成功", "result": serializer.data})
​
    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response({"code": 200, "msg": "删除成功"})
  • 数据模型表

from django.db import models
​
# Create your models here.
from django.db import models
​
​
# Create your models here.
class Student(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    gender = models.IntegerField(choices=((0, '未知'), (1, '男'), (2, '女')))
​
    @property
    def new_name(self):
        return self.name + "_nb"
​
​
# book数据表
class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.IntegerField()
    publish = models.ForeignKey(to='Publish', on_delete=models.SET_NULL, null=True)
    # 作者和图书是多对多关系,需要中间表
    # Django中orm优化了,无序手动创建 使用ManyToMany可以自动创建
    # authors不是字段,是一个中间表
    authors = models.ManyToManyField(to='Author')
​
    def publish_detail(self):
        return {"name": self.publish.name, "city": self.publish.city, "addr": self.publish.addr}
​
    def author_list(self):
        author_all = self.authors.all()
        author_list = []
        for author in author_all:
            author_list.append({"name": author.name, "age": author.age})
        return author_list
​
​
class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)
​
​
class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    addr = models.CharField(max_length=32)
  • 序列化类

from rest_framework import serializers
​
from app01.models import Book
​
​
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['name', 'price', 'publish', 'authors', 'publish_detail', 'author_list']
        extra_kwargs = {
            "publish": {"write_only": True},
            "authors": {"write_only": True},
            "publish_detail": {"read_only": True},
            "author_list": {"read_only": True},
        }
​

【APIView源码分析】

# APIView
    1 它继承自django的View,所以必须写get、post、put、delete方法
    2 在它里面还有类属性:parser_class,render_class
        -使用顺序是:视图类自己--》项目配置文件--》drf内置配置
        -render_class=api_settings.DEFAULT_RENDERER_CLASSES
        -api_settings是drf的配置,如果咱们项目配置文件配了  REST_FRAMEWORK={},会覆盖掉原来drf默认的配置
    3 读APIViwez--》as_view和dispatch
        在APIView里面做了下面这些
        -3.1 包装了新的request: 
            -新的request对象:request._request
            -视图类的对象 :self.requset 就是新的request
        -3.2 去除了csrf认证
            -csrf_exempt(view)
        -3.3 做了三大认证:认证,权限,频率
            self.perform_authentication(request)
            self.check_permissions(request)
            self.check_throttles(request)
        -3.4 做了全局异常处理:后续要学定制返回格式
            在try里
   4 总结:
    当使用的时候
    def get(self,request):
        # request 新的
        # csrf没了
        # 执行完三大认证,才能到这里
        # 出了异常,会有捕获
    request._request
    self.request=request            

【2】基于GenericAPIView + 序列化类 + Response写5个接口

  • views.py

# 基于genericAPIView + Response
from rest_framework.generics import GenericAPIView
​
​
class BookView(GenericAPIView):
    # 两个类属性
    # 1 要序列化的数据、
    queryset = Book.objects.all()
    # 2 序列化类
    serializer_class = BookSerializer
​
    def post(self, request):
        # self.get_serializer 拿到在类属性上配置的serializer_class的值
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response({"code": 200, "msg": "添加成功", "result": serializer.data})
​
    def get(self, request):
        books = self.get_queryset()
        serializer = self.get_serializer(instance=books, many=True)
        return Response({"code": 200, "msg": "查看成功", "result": serializer.data})
​
​
class BookDetailView(GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
​
    def put(self, request, pk):
        # 根据传入的pk值,拿到一条记录
        # self.get_object()---》 根据queryset 配置所有数据和pk 获取一条数据
        book = self.get_object()
        serializer = self.get_serializer(instance=book, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response({"code": 200, "msg": "修改成功", "result": serializer.data})
​
    def get(self, request, pk):
        book = self.get_object()
        serializer = self.get_serializer(instance=book)
        return Response({"code": 200, "msg": "查看成功", "result": serializer.data})
​
    def delete(self, request, pk):
        self.get_object().delete()
        return Response({"code": 200, "msg": "删除成功"})

继承GenericAPIView后使用了两个类属性和三个方法

类属性:

    # 所有数据
    queryset = Book.objects.all()
    # 序列化类
    serializer_class = BookSerializer

方法:使用对象调用 self.方法

# 和之前的序列化类一样
serializer = self.get_serializer(instance=book, data=request.data)
# 所有数据
books = self.get_queryset()
# 根据pk值获取单条数据
book = self.get_object()

【总结】假设用户再写其他类的5个接口 代码只需要更改两个类属性

    # 所有数据
    queryset = Book.objects.all()
    # 序列化类
    serializer_class = BookSerializer

【GenericAPIView源码分析】

1 继承了APIView ---》APIView具备的所有特点,GenericAPIView都有,在此基础上扩展了一些用法
2 多了几个类属性
	queryset			# 数据源,直接给列表 或 QuerySet
    serializer_class	# 序列化类
    lookup_field = 'pk'	# get_object,没有传参数,但它是按pk拿数据
    lookup_url_kwarg = None		# lookup_url_kwarf=1
    filter_backends = api_settings.DEFAULT_FILTER_BACKENDS # 过滤
    pagination_class = api_settings.DEFAULT_PAGINATION_CLASS # 分页    
    
3 多了几个方法
	(1)get_queryset:本质就是返回了self.queryset 数据源
    	def get_queryset(self):
                queryset = self.queryset
                if isinstance(queryset, QuerySet):
                    queryset = queryset.all() # 因为self.queryset 会先执行--》为了保证数据最新
                return queryset
    (2)get_serializer:直接实例化得到序列化类的对象--》self.serializer_class
        def get_serializer(self, *args, **kwargs):
            serializer_class = self.get_serializer_class()
            kwargs.setdefault('context', self.get_serializer_context())
            return serializer_class(*args, **kwargs)
        def get_serializer_class(self): # 通过重写它,定制序列化,反序列化分开使用
            return self.serializer_class
    # 总结:
        	-内部方法中拿序列化类的对象:get,post--》都是通过self.get_serializer()
            -但是我们可以通过【重写】get_serializer_class,返回不同序列化类来控制:self.get_serializer()拿到的序列化类不同
    # 示例
    # 要求,序列化用 BookSerialzier 序列化类,反序列化用 BookWriteSerialzier
class BookView(ListCreateAPIView):
    queryset = Book.object.all()
    serializer_class = BookSerialzier   
    def get_serializer_class(self):
        if self.request.method=='GET':
            return BookSerialzier
        else:
            return BookWriteSerialzier
    (3)get_object:根据 lookup_field 指定的对应参数,从数据源中 过滤出单个对象

【补充】

#1  对象使用类属性
	对象.属性名即可
    类.属性名即可
   
    
#2  如果对象中有跟类属性同名的,会怎么样? 优先用自己的
class Person:
    school='清华大学'
person2=Person()
person2.school='北京大学'  # 只会改对象自己的,不会改类的
print(person2.school)  #  一旦对象自己有了,优先用对象自己的    '北京大学'

person=Person()
print(person.school) #对象没有,就用类的  清华大学

【3】5个视图扩展类 + GenericAPIView + 序列化类 + Response写接口

# 5个视图扩展类 + GenericAPIView + 序列化类 + Response写接口
from rest_framework.generics import GenericAPIView
# 5个视图扩展类 
from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin, CreateModelMixin, DestroyModelMixin, \
    ListModelMixin


class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
    # 两个类属性
    # 1 要序列化的数据、
    queryset = Book.objects.all()
    # 2 序列化类
    serializer_class = BookSerializer

    def post(self, request):
        return super().create(request)

    def get(self, request):
        return super().list(request)


class BookDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def put(self, request, pk):
        return super(BookDetailView, self).update(request, pk)

    def get(self, request, pk):
        return super(BookDetailView, self).retrieve(request, pk)

    def delete(self, request, pk):
        return super(BookDetailView, self).destroy(request, pk)
    
【注意】
  • 5个视图扩展类必须配合GenericAPIView使用

【5个视图扩展类的源码分析】

from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin, CreateModelMixin, DestroyModelMixin,ListModelMixin

# CreateModelMixin
class CreateModelMixin:

    def create(self, request, *args, **kwargs):
        # 拿到序列化类,实例化得到对象
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        # 保存单独封装
        # 可以通过重写perform_create 在保存之前或者保存之后做的处理
        self.perform_create(serializer)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def perform_create(self, serializer):
        # 保存之前要做的处理
        serializer.save()
        # 保存之后要做的处理
        
ListModelMixin::list
	-获取所有
DestroyModelMixin: destroy
	-删除
    -perform_destroy
RetrieveModelMixin: retrieve
    -拿单条数据
UpdateModelMixin:update
	-更新
    -perform_update

【4】9个视图子类

# 9个视图子类---这是真是的视图类
from rest_framework.generics import ListAPIView, CreateAPIView, RetrieveAPIView, UpdateAPIView, DestroyAPIView
from rest_framework.generics import ListCreateAPIView
from rest_framework.generics import RetrieveUpdateDestroyAPIView, RetrieveUpdateAPIView, RetrieveDestroyAPIView


class BookView(ListCreateAPIView):
    # 两个类属性
    # 1 要序列化的数据、
    queryset = Book.objects.all()
    # 2 序列化类
    serializer_class = BookSerializer

    # 定制新增之后返回格式
    def create(self, request, *args, **kwargs):
        res = super().create(request)
        return Response({"code": 200, "msg": "新增成功", "result": res.data})


class BookDetailView(RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

【9个视图子类源码分析】

1 ListAPIView
	-GenericAPIView+ListModelMixin+get方法
    -只写一个查询所有接口
    class BookView(ListAPIView):
        queryset=xx
        serializer_class=yy
2 CreateAPIView
	-GenericAPIView+CreateModelMixin+post方法
    -只写一个新增接口
    class BookView(CreateAPIView):
        queryset=xx
        serializer_class=yy
        def perform_save(self):
            pass
3 RetrieveAPIView
	-GenericAPIView+RetrieveModelMixin+get方法
    -只写一个查询所有接口
    class BookView(ListAPIView):
        queryset=xx
        serializer_class=yy
4 UpdateAPIView
	修改
5 DestroyAPIView
	删除
6 ListCreateAPIView
	-GenericAPIView+ListModelMixin+CreateModelMixin+post方法+get方法
    -写一个查询所有接口和新增接口
    class BookView(ListCreateAPIView):
        queryset=xx
        serializer_class=yy
        
7 RetieveUpdateDestroyAPIView
	-GenericAPIView+RetrieveModelMixin+UpdateModelMixin++DestroyModelMixin+put方法+get方法+delete方法
    -写一个查询单条,修改一条,删除一条
    class BookView(RetrieveUpdateDestroyAPIView):
        queryset=xx
        serializer_class=yy
8 RetieveUpdateAPIView
	查询、修改
9 RetieveDestroyAPIView
	查询、删除

【5】视图集

  • 使用视图集ModelViewSet, ReadOnlyModelViewSet时路由就需要改变一些了,添加映射

from django.urls import path
from .views import BookView

# 继承ModelViewSet后路由就变了,需要映射
urlpatterns = [
    path('books/', BookView.as_view({"get": "list", "post": "create"})),
    path('books/<int:pk>/', BookView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
]
  • views.py

# 视图集
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet


class BookView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # 这个类中没有 get   post       get   put    delete方法
    # 相对应的是  list retrieve    create  update  destroy方法
c
    # 需要定制输出格式的时候就需要重写list、retrieve、create、update、destroy方法


# 只读里面只有两个方法 mixins.RetrieveModelMixin,mixins.ListModelMixin
class BookRView(ReadOnlyModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

【视图集源码分析】

# ModelViewSet,ReadOnlyModelViewSet
# ModelViewSet:5个接口都有 里面没有get,post,delete方法了,因为路由写法变了,是映射的
    CreateModelMixin
    ListModelMixin
    DestroyModelMixin
    RetrieveModelMixin
    UpdateModelMixin
    GenericViewSet
        -GenericAPIView
        -ViewSetMixin
#ReadOnlyModelViewSet:查询单条和所有接口
    ListModelMixin
    RetrieveModelMixin
    GenericViewSet
        -GenericAPIView
        -ViewSetMixin       
# ViewSetMixin:控制路由写法变了的类。以后只要路由写法变了,必须继承它
	-重写了urls.py中的as_view,必须传字典做映射的方式,否则报错
    	-原理是通过反射:实现了MyViewSet.as_view({'get': 'list', 'post': 'create'})
        -要执行get的时候,本质执行的是 list  
    -好处,以后视图类,可以写任意名字的方法,只要路由做好映射即可
    	-路由:path('send_sms/', UserView.as_view({'get':'send_sms'})),
        -视图类:
        class UserView(ViewSetMixin,APIView):
            def send_sms(self):
                print('真发短信')
                return Response({'code':100,'msg':"短信发送成功"})  
        # ViewSet = ViewSetMixin,APIView
# GenericViewSet=ViewSetMixin+GenericAPIView
from rest_framework.response import Response
class UserDetailView(GenericViewSet):
    serializer_class = 某个序列化类
    def login(self):
        serializer=self.get_serializer()
        serializer.is_valiad()
        return Response({'code':100,'msg':"短信发送成功"})

【6】视图层总结-小案例选择哪些视图类继承

# 1 发送短信接口
	-APIView+get方法
    -ViewSet+send_sms方法
# 3 查询所有,查询单条
	-路由:
        path('books/', BookView.as_view({'get':'list'})),
        path('books/<int:pk>', BookView.as_view({'get':'retrieve'})),
    -视图类
    	class BookView(ReadOnlyModelViewSet):
            queryset=
            serializer_class=
            
# 4 查询所有,删除一条
	-写俩:ListAPIView   DestroyAPIView
    -写一个:
    -路由:
        path('books/', BookView.as_view({'get':'list'})),
        path('books/<int:pk>', BookView.as_view({'delete':'destroy'})),
    -视图类
    	class BookView(GenericViewSet,ListModelMixin,DestroyModelMixin):
            queryset=
            serializer_class=
            
            
# 5 总结
	1 只要想路由变了:ViewsetMixin
    2 只要想序列化,反序列化,就用GenericAPIView
    3 即想路由变了又想序列化,反序列化  GenericViewSet
    4 即想路由变了又想序列化,反序列化 ,还想写某一个或某几个接口 GenericViewSet+5个视图扩展类
  • 25
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于使用DRFDjango Rest Framework)和Vue的数据导入和导出,可以按照以下步骤进行操作: 1. 在Django中创建一个可以导出数据的API视图。你可以使用DRF的`APIView`类作为基类,并在`get`方法中编写逻辑来导出数据。例如,你可以使用`HttpResponse`返回CSV格式的数据。 ```python from django.http import HttpResponse from rest_framework.views import APIView class ExportDataAPIView(APIView): def get(self, request, format=None): # 导出数据的逻辑 # 数据可以从数据库或其他来源获取 # 创建CSV数据 csv_data = "col1,col2,col3\nvalue1,value2,value3\n" response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename="data.csv"' response.write(csv_data) return response ``` 2. 在Vue中创建一个导出数据的页面或组件。你可以使用`axios`库发送GET请求到Django的API视图,并将响应保存为CSV文件并进行下载。 ```javascript import axios from 'axios'; const exportData = () => { axios.get('/api/export-data/', { responseType: 'blob' }) .then(response => { const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', 'data.csv'); document.body.appendChild(link); link.click(); }) .catch(error => { console.error(error); }); }; exportData(); ``` 3. 对于数据的导入,你可以在Django中创建一个可以接收上传文件的API视图。你可以使用DRF的`APIView`类,并在`post`方法中编写逻辑来处理上传的文件。 ```python from rest_framework.parsers import MultiPartParser from rest_framework.views import APIView class ImportDataAPIView(APIView): parser_classes = [MultiPartParser] def post(self, request, format=None): file = request.FILES['file'] # 处理上传文件的逻辑
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值