restframework 复习入坑笔记

前言:当初第一次接触时一脸懵逼,为了赶进度暂时放下了, 现在重新捡起来了, 略有收获, 但是坑太多, 暂时填补了,只等日后时机成熟再填坑。

写在前面:

1) PublishSerializers(queryset, many=True),  PublishSerializers(model)   serializers可以序列化model和queryset, 序列化queryset时,因为是多个对象, 要加many=True。

2)别忘了在settings中INSTALLED_APPS中注册

3)request.data  拿到的是post和put请求

4)request.GET  request._request.GEt 拿的才是get数据

5)还有restframework 中的request 不是以前的request,它变了,request._request才是以前的request 

6) Resonse  返回更友好的数据

7)如127.0.0.1:8000/books/?format=json        浏览器访问,可以显示json数据

 

一  序列化

models.py

from django.db import models


class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.IntegerField()
    pub_date = models.DateField(null=True)
    publish = models.ForeignKey("publish", on_delete=models.CASCADE)
    authors = models.ManyToManyField("Author")

    def __str__(self):
        return self.title


class Publish(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField(null=True)

    def __str__(self):
        return self.name


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    def __str__(self):
        return self.name

url.py

from django.contrib import admin
from django.urls import path, re_path
from app001 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('publishes/', views.PublishView.as_view(), name="publish"),
    re_path(r'publishes/(?P<pk>\d+)/$', views.PublishDetailView.as_view(), name="detailpublish"),
    path('books/', views.BookView.as_view(), name="book"),
    re_path(r'books/(\d+)/$', views.BookDetailView.as_view(), name="detailbook")
]

myserlizer.py (知道拼错了, 将错就错, 还有坑太特么多了, mmp,暂时没精力解决了,至以后的自己)

两种序列化方法

from rest_framework import serializers
from app001 import models


# 两种序列化方法, 最好用model的
class PublishSerializers(serializers.Serializer):
    name = serializers.CharField(max_length=32)
    email = serializers.EmailField()
# 日了狗, 用这个序列化,发get没问题, 发post就说create方法有问题,重写create也不行


class PublishModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.Publish
        fields = "__all__"


class BooksSerializers(serializers.Serializer):
    title = serializers.CharField(max_length=32)
    price = serializers.IntegerField()
    pub_date = serializers.DateField()
    publish = serializers.CharField(source="publish.name")
    # authors = serializers.CharField(source="authors.all")
    authors = serializers.SerializerMethodField()
    publish = serializers.CharField(source="publish.pk", read_only=True)

# 凉凉, 发post 还是有问题

    def get_authors(self, obj):
        temp = []
        for obj in obj.authors.all():
            temp.append(obj.name)
        return temp
# ################################################################


class BooksModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = "__all__"

    # publish = serializers.HyperlinkedIdentityField(
    #     view_name="detailpublish",
    #     lookup_field="publish_id",
    #     lookup_url_kwarg="pk"
    # )
    # 自定义字段,显示成一个超链接, url要全部制定name参数
    # views还要加参数BooksModelSerializers(book_list, many=True, context={'request': request})
    # 同样post凉凉

    # 默认是返回一对多,多对多的主键
    # 如果想返回名字要自定义, 然后在views重写create
    # publish = serializers.CharField(source="publish.name")
    #  发put还要YM重写update
    # 一对多显示name, 要重写create
    # authors = serializers.CharField(source="authors.all")
    # "<QuerySet [<Author: えなこ>, <Author: まこち>]>", post凉凉

    # 注意下下面有个问题没解决
    # 但是下面的重构authors字段 这是显示作者的名字,并不需要重写create, get请求时显示正常, 但是post时会出现问题
    # 如果重写authors, validated_data拿不到authors,book.authors.add(*validated_data["authors"])没法绑定关系
    # 所以不能和create共存,就是说当post时只能做到让一对一或多对多显示指定名字
    # authors = serializers.SerializerMethodField()
    #
    # def get_authors(self, obj):
    #     temp = []
    #     for obj in obj.authors.all():
    #         temp.append(obj.name)
    #     return temp

    # def create(self, validated_data):
    #     print("xxxxxx", validated_data)
    #     book = models.Book.objects.create(title=validated_data["title"], price=validated_data["price"], pub_date=validated_data["pub_date"], publish_id=validated_data["publish"]["name"])
    #     book.authors.add(*validated_data["authors"])
    #     return book

views.py

from rest_framework.response import Response
from app001.models import *
from rest_framework.views import APIView
from app001.myserilizer import *


class PublishView(APIView):
    def get(self, request):
        publish_list = Publish.objects.all()
        ps = PublishModelSerializers(publish_list, many=True)
        return Response(ps.data)

    def post(self, request):
        ps = PublishModelSerializers(data=request.data)
        if ps.is_valid():
            ps.save()
            return Response(ps.data)
        else:
            return Response(ps.errors)


class PublishDetailView(APIView):
    def get(self, request, pk):
        publish = Publish.objects.filter(pk=pk).first()
        ps = PublishModelSerializers(publish)
        return Response(ps.data)

    def put(self, request, pk):
        publish = Publish.objects.filter(pk=pk).first()
        ps = PublishModelSerializers(publish, data=request.data)
        # 加many=True  不行会报错, 所以面对model还是别好奇加many参数会怎样
        if ps.is_valid():
            ps.save()
            return Response(ps.data)
        else:
            return Response(ps.errors)

    def delete(self, request, pk):
        Publish.objects.filter(pk=pk).delete()
        return Response()


class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        bs = BooksModelSerializers(book_list, many=True, context={'request': request})
        return Response(bs.data)

    def post(self, request):
        bs = BooksModelSerializers(data=request.data)
        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return Response(bs.errors)
    """
    postman 发post的数据
        {
            "title": "第四本书",
            "price": 123214,
            "pub_date": "2011-11-11",
            "publish": 1,
            "authors": [1, 2]
        }
    """


class BookDetailView(APIView):
    def get(self, request, id):
        book = Book.objects.filter(pk=id).first()
        bs = BooksModelSerializers(book, context={'request': request})
        return Response(bs.data)

    def put(self, request, id):
        book = Book.objects.filter(pk=id).first()
        bs = BooksModelSerializers(book, data=request.data)
        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return Response(bs.errors)

    def delete(self, request, id):
        Book.objects.filter(pk=id).delete()
        return Response()

二 重写视图的几种方法

1)mixins

views.py

from rest_framework import mixins
from rest_framework import generics


class BookView(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BooksModelSerializers

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

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)


class BookDetailView(mixins.RetrieveModelMixin, mixins.DestroyModelMixin, mixins.UpdateModelMixin, generics.GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BooksModelSerializers

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

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)



urls.py
    path('books/', views.BookView.as_view(), name="book"),
    re_path(r'books/(?P<pk>\d+)/$', views.BookDetailView.as_view(), name="detailbook")

2)generics

views.py
from rest_framework import generics


class BookView(generics.ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BooksModelSerializers


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

urls.py

    path('books/', views.BookView.as_view(), name="book"),
    re_path(r'books/(?P<pk>\d+)/$', views.BookDetailView.as_view(), name="detailbook")

3)viewsets

views.py

from rest_framework import viewsets


class BookModelView(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BooksModelSerializers


urls.py

path('books/', views.BookModelView.as_view({"get": "list", "post": "create"}), name="book"),
    re_path(r'books/(?P<pk>\d+)/$', views.BookModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"}),

三 认证

rest_framework的认证逻辑是自己写的,如下面的认证,看看能否在url拿到正确的token信息, 然后返回指定形式的内容

1)继承object, 要写authenticate_header

from rest_framework import exceptions

class TokenAuth(object):
    def authenticate(self, request):
        token = request.GET.get("token")
        token_obj = Token.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationField("验证失败")
        else:
            return token_obj.user.name, token_obj.token
            #      self.user             self,auth   
     def authenticate_header(self, request):
         # 不定义这个函数会报错
         pass

2) 继承BaseAuthentication

from rest_framework.authentication import BaseAuthentication
def TokenAuth(BaseAuthtication):
    pass

使用的时候:

class Bookview(APIView):
     authentication_classes = [TokenAuth,]


# 或者

class BookModelView(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BooksModelSerializers
    authentication_classes = TOkenAuth

想让它全局生效时:

在settings中加

REST_FRAMEWORK = {
         "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.TokenAuth",],
          # 所在位置
}

当设置全局,但是某个部分不需要用它,只需要把它自己的设置成

authentication_classes = []

四 权限

逻辑依然是自己写的, 只是用人家的钩子

class SVIPPERmission(object):
    def has_permission(self, request. view):
         username = request.user
         # 经过认证, 拿到登陆人的request.user
         user_type = User.objects.filter(name=username).first().user_type
         if user_type == 3:
             return True
            # 通过权限
         else:
            return False

使用时:

跟前面的认证一样

class Bookview(APIView):
     authentication_classes= [TokenAuth,]
     permission_classes = [SVIPPermission,]


# 或者

class BookModelView(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BooksModelSerializers
    authentication_classes = TOkenAuth
    permission_classes = SVIPPermission

全局:

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",]
}

五 频率

自己写的频率

在app01.service.throttles.py中:

from rest_framework.throttling import BaseThrottle

VISIT_RECORD={}
class VisitThrottle(BaseThrottle):

    def __init__(self):
        self.history=None

    def allow_request(self,request,view):
        remote_addr = request.META.get('REMOTE_ADDR')
        print(remote_addr)
        import time
        ctime=time.time()

        if remote_addr not in VISIT_RECORD:
            VISIT_RECORD[remote_addr]=[ctime,]
            return True

        history=VISIT_RECORD.get(remote_addr)
        self.history=history

        while history and history[-1]<ctime-60:
            history.pop()

        if len(history)<3:
            history.insert(0,ctime)
            return True
        else:
            return False

    def wait(self):
        import time
        ctime=time.time()
        return 60-(ctime-self.history[-1])

views中

class BookViewSet(generics.ListCreateAPIView):
    throttle_classes = [VisitThrottle,]
    queryset = Book.objects.all()
    serializer_class = BookSerializers

设置为全局时

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",]
}

利用自带,人家写好的

在app01.service.throttles.py修改为:

class VisitThrottle(SimpleRateThrottle):

    scope="visit_rate"
    def get_cache_key(self, request, view):

        return self.get_ident(request)

设置

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
    "DEFAULT_THROTTLE_RATES":{
        "visit_rate":"5/m",
    }
}

五 解析器

感觉没什么用,默认自带三个常用解析器

from rest_framework.parsers import JSONParser, FormParser, MultiPartParser, FileUploadParser

class xxview(APIView):
    parser_classes = [JSONParser, ]

六 路由

针对的是.ModelViewSet视图,它的url写起来太麻烦

from rest_framework import viewsets


class BookModelView(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BooksModelSerializers


"""
 path('books/', views.BookModelView.as_view({"get": "list", "post": "create"}), name="book"),
 re_path(r'books/(?P<pk>\d+)/$', views.BookModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"}), name="detailbook")
"""

蓑衣用到路由精简代码,在ulrs.py中

from django.contrib import admin
from django.urls import path, re_path, include
from app001 import views
from rest_framework import routers

routers = routers.DefaultRouter()
routers.register('book', views.BookModelView)
# 'book'是访问路径, 可以注册多个

rlpatterns = [
    # path('books/', views.BookModelView.as_view({"get": "list", "post": "create"}), name="book"),
    # re_path(r'books/(?P<pk>\d+)/$', views.BookModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"}), name="detailbook")
    path('', include(routers.urls))
    # 只要这么写
]

可以正常访问页面

http://127.0.0.1:8000/book/http://127.0.0.1:8000/book/1, http://127.0.0.1:8000/book/1.json  

http://127.0.0.1:8000/book/1/?format=json     json格式,

 

七 分页

from rest_framework.pagination import PageNumberPagination
class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        pnp = PageNumberPagination()
        books_page = pnp.Paginate_queryset(book_list, request, self)
        bs = BookModelSerializers(books_page, many=True, context={'request': request})
        return Response(bs.data)

在settings中

全局

REST_FRAMEWORK =  { 
           "PAGE_SIZE": 1
}

# 访问 url/?page=1

也可以自定制

from rest_framework.pagination import PageNumberPagination

class MyPageNumberPagination(PageNumberPagination):
    page_size = 2                      # 每个页面几条数据
    page_query_param = 'page'          # /?page=1
    page_size_query_param = 'size'     # 加了这个参数可以访问 /?page=2&size=x, 强制显示x页
    max_page_size = 3                  # 规定上面的x不能大于3

对于封装完全的modelViewset

from rest_framework import viewsets


class BookModelView(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BooksModelSerializers
    pagination_class = MyPageNumberPagination

八 响应器

from rest_framework.response import Response

九 解析器

如下

十 版本控制

views.py

from rest_framework import viewsets
from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
from rest_framework.versioning import QueryParameterVersioning, URLPathVersioning


class BookModelView(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BooksModelSerializers
    renderer_classes = [JSONRenderer, BrowsableAPIRenderer]
    # 局部定义的解析器BrowsableAPIRenderer让json数据变更好看, 默认就是这几个, 根本无需修改
    versioning_class = QueryParameterVersioning
    # 版本 类似 http://127.0.0.1:8000/book/?version=v1

    # versioning_class = URLPathVersioning
    # 这个的url形如: http://127.0.0.1:8000/v1/book/    还得自己配置url, 不知道怎么和router连用

settings.py

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': ['rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer'],
    # 全局设置渲染器
    'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.QueryParameterVersioning',
    # 全局版本控制,
    'ALLOWED_VERSIONS': ['v1', 'v2'],
    # 允许访问的版本
    'VERSION_PARAM': 'version',
    # 版本的参数, 默认就是version
    'DEFAULT_VERSION': 'v1'
    # 默认版本, 不加参数, 默认
}

特别的当使用versioning_class = URLPathVersioning, 要配置url

urlpatterns = [
     re_path(r'^(?P<version>\w+)/book/$', xxxxxx)

可以在后端拿到版本信息

print(request.version)

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值