DRF十大組件的作用和使用方法

認(rèn)證

  • 作用: 檢測用戶是都登錄
  • 使用:
#自定義認(rèn)證類(繼承自object)
    class MyBaseAuthentication(Object):

        def authenticate(self, request):
            #完成認(rèn)證邏輯
            
        def authenticate_header(self, request):
        
            pass

#自定義認(rèn)證類(繼承自BaseAuthentication)
    from rest_framework.authentication import BaseAuthentication
    from rest_framework.exceptions import AuthenticationFailed
    class MyBaseAuthentication(BaseAuthentication):
        
        def authenticate(self, request):
            #完成認(rèn)證邏輯


    # 登錄用戶才能訪問所有注冊用戶列表(局部使用設(shè)置)
    authentication_classes = [MyBaseAuthentication,]

    #設(shè)置為空列表镣煮,就不走認(rèn)證流程了(全局設(shè)置后,要想單個(gè)視圖不走認(rèn)證)
    authentication_classes = []

#全局設(shè)置
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES':['util.authentication.MyBaseAuthentication',],
    }

    # 匿名用戶(用戶未登錄的情況下拐袜,可以設(shè)置匿名用戶信息( user圾另、auth))
    # 必要條件:不管是全局還是視圖中都沒有設(shè)置認(rèn)證類
    REST_FRAMEWORK = {
        'UNAUTHENTICATED_USER':lambda :'匿名用戶',
        'UNAUTHENTICATED_TOKEN':lambda :'1234',
    }

權(quán)限

  • 作用:某些接口只能是特定的用戶才能訪問
  • 使用方法:
#自定義權(quán)限類(Object)
     class MyPermission(object):
         message = 'vip用戶才能訪問'
         def has_permission(self,request,view):
             #完成權(quán)限邏輯
             #返回True,表示有權(quán)限訪問
             #返回Flase蘸吓,表示沒有權(quán)限訪問

#自定義權(quán)限類(BasePermission)
    from rest_framework.permissions import BasePermission
    class MyPermission(BasePermission):
            message = 'vip用戶才能訪問'
            def has_permission(self,request,view):
                #完成權(quán)限邏輯
                #返回True,表示有權(quán)限訪問
                #返回Flase车海,表示沒有權(quán)限訪問

#局部配置配置(在視圖中配置)
    #設(shè)置權(quán)限類(局部使用設(shè)置)
    permission_classes = [MyPermission,]

    #設(shè)置為空列表枢舶,就不走權(quán)限流程了(全局設(shè)置后赶么,要想單個(gè)視圖不走權(quán)限設(shè)置了)
    permission_classes = []

#全局設(shè)置
   REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES':['util.permission.MyPermission',],
   {

節(jié)流

  • 作用:根據(jù)用戶和ip地址用戶的唯一標(biāo)示限制用戶的訪問頻率
  • 使用方法
#自定義(Object)
    RECORD_VISITS = {}
    class VisitThrottle(object):
        def __init__(self):
            #獲取用戶的訪問歷史
            self.history = []
        
        def allow_request(self, request, view):
            #allow_request是否允許方法
            #True 允許訪問
            #False 不允許訪問
            #獲取用戶的IP地址
            # ip_adress = request._request.META.get('REMOTE_ADDR')
            # key = ip_adress
            
            #基于用戶
            token = request.auth
            key = token
            
            currenttime = time.time()
            if key not in RECORD_VISITS:
                #當(dāng)前的IP地址沒有訪問過服務(wù)器
                RECORD_VISITS[key] = [currenttime]
                return True
            #獲取訪問歷史記錄
            visit_history = RECORD_VISITS[key]
            self.history = visit_history
            
            #[ 12:01:00, 12:01:25, 12:02:25]            12:03:30  - 60
            #                                           12:02:30
            while visit_history and visit_history[-1] < currenttime - 60:
                visit_history.pop()

        if len(visit_history) < 5:
            #每分鐘訪問5次
            visit_history.insert(0,currenttime)
            return True
                
        return False  # False表示訪問頻率太高被限制
        
        def wait(self):
            # 12:03:03
            # [12:02:58,12:02:55,12:02:50,12:02:45,12:02:40]
            first_time = self.history[-1]
            return 60 - (time.time() - first_time)
 #自定義(SimpleRateThrottle)
    class MySimpleRateThrottle(SimpleRateThrottle):
        scope = 'unlogin'
        def get_cache_key(self, request, view):
            #根據(jù)ip或者用戶標(biāo)示獲取用戶的訪問記錄
            return self.get_ident(request)
            #  return request.user.name
 #局部使用
        #設(shè)置節(jié)流的類(局部使用設(shè)置)
        throttle_classes = [VisitThrottle,]
        throttle_classes = [MySimpleRateThrottle,]

        #設(shè)置為空列表棠笑,就不進(jìn)行節(jié)流設(shè)置了
         throttle_classes = []
# 全局設(shè)置
        REST_FRAMEWORK = {
            'DEFAULT_THROTTLE_RATES':{
                'unlogin':'5/m',
            },
            'DEFAULT_THROTTLE_CLASSES':['util.throttle.MySimpleRateThrottle',],
        }

版本

  • 作用:判斷用戶請求的Api是否有效(公司版本迭代時(shí)做兼容)
  • 使用方法
自定義(object):(url地址傳參)
     class MyPathVersioning(object):
         def determine_version(self,request, *args, **kwargs):
             # 獲取用戶傳遞的版本參數(shù)(version)
             # version = request._request.GET.get('version')
             version = request.query_params.get('version')
             return version

    #設(shè)置自定義的版本類
   # versioning_class = MyPathVersioning
   # 使用DRF自帶的版本類QueryParameterVersioning
   from rest_framework.versioning import QueryParameterVersioning
    # 在視圖中
    versioning_class = QueryParameterVersioning

    #如果需要做版本的默認(rèn)和限制,需要在settings中設(shè)置
    REST_FRAMEWORK = {
        'DEFAULT_VERSION':'v1',
        'ALLOWED_VERSIONS':['v1','v2','v3'],
        'VERSION_PARAM':'version',
    }

    # #設(shè)置默認(rèn)的版本
    # default_version = api_settings.DEFAULT_VERSION
    # #設(shè)置允許的版本
    # allowed_versions = api_settings.ALLOWED_VERSIONS
    # #設(shè)置版本的參數(shù)
    # version_param = api_settings.VERSION_PARAM

#使用DRF自帶的版本類URLPathVersioning

    from rest_framework.versioning import URLPathVersioning

    # 在視圖中(局部使用)
    versioning_class = URLPathVersioning
##
#    versioning_class = None

    #如果需要做版本的默認(rèn)和限制禽绪,需要在settings中設(shè)置
    REST_FRAMEWORK = {
        'DEFAULT_VERSION':'v1',
            'ALLOWED_VERSIONS':['v1','v2','v3'],
            'VERSION_PARAM':'version',
    }

    #全局設(shè)置
    REST_FRAMEWORK = {
        'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
    }

解析器

  • 作用:在POST請求中獲取表單參數(shù)時(shí),有時(shí)在_request.POST中拿不到數(shù)據(jù)
  • 使用方法
from rest_framework.parsers import JSONParser,FormParser

    # FormParser
    # 當(dāng)前端發(fā)送過來的數(shù)據(jù)是json數(shù)據(jù)的時(shí)候
    # content-type:application/x-www-form-urlencoded
    # post請求的數(shù)據(jù)在_request.POST拿到數(shù)據(jù)
    # 發(fā)送到后端的數(shù)據(jù)格式productId=123&productName=宋&userId=1
    productId = request._request.POST.get('productId')
    productName = request._request.POST.get('productName')
    userId = request._request.POST.get('userId')
    print(productId,productName,userId)

    # JSONParser
    # 當(dāng)前端發(fā)送過來的數(shù)據(jù)是json數(shù)據(jù)的時(shí)候
    # content-type:application/json
    # post請求的數(shù)據(jù)在_request.POST已經(jīng)獲取不到了
    # 在_request.body可以拿到
    # #發(fā)送到后端的數(shù)據(jù)格式{'productId': 123, 'productName': '宋', 'userId': 1}
    data = request._request.body
    import json
    data = json.loads(data)
    print(data)

    #只用調(diào)用request.data的時(shí)候才使用上了解析器
    data = request.data
    print(data)

序列化

  • 作用:對查詢出的結(jié)果queryset進(jìn)行序列化洪规,返回
  • 使用方法
第一種方式(serializers.Serializer)
        class xxxxSerializer(serializers.Serializer):
            username = serializers.CharField()
            #用戶的id
            id = serializers.IntegerField()
            # 用戶類型(普通用戶印屁、VIP用戶)
            #type = serializers.IntegerField()
            type = serializers.CharField(source="get_type_display")
            # 1:男  2:女
            #自定義序列化方法
            gender = serializers.SerializerMethodField()
            # 出生日期
            birthday = serializers.DateTimeField(format='%Y-%m-%d')
            #自定義序列化方法的方法民命規(guī)范:def get_字段名(self,row)
            #生成url地址
            #序列化時(shí)返回用戶詳情的url地址
            url = serializers.HyperlinkedIdentityField(
                view_name ='userdetail',lookup_field='id',lookup_url_kwarg ='pk')
           # url(r"^(?P<version>[v1|v2]+)/userdetail/(?P<pk>\d+)/",UserDetailView.as_view(),name='userdetail'),
            def get_gender(self,row):
                ##row -> User()
                if row.gender == 1:
                    return "男"
                elif row.gender == 2:
                    return "女"

            # 如果使用serializers.Serializer)序列化的類保存數(shù)據(jù)時(shí),需要重寫create
            def create(self, validated_data):
                 instance = models.User.objects.create(**validated_data)
                 return instance
第二種方式(serializers.ModelSerializer)
    class UserListSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.User
            #fields = "__all__"
            fields = ["id","username"]
  • 作用:2.對請求的數(shù)據(jù)進(jìn)行驗(yàn)證(POST)
  • 使用方法
class RegisterUserSerializer(serializers.ModelSerializer):
        #用戶名
        username = serializers.CharField(error_messages=
             {
             'required':'用戶名不能為空'
             },
        )
        #密碼(A a-z 0-9,不低于8位)
        password = serializers.CharField()
         
         #自定義驗(yàn)證方法(validate_字段名)
         def validate_password(self,value):
             #value -> password
             import re
             from rest_framework.exceptions import ValidationError
             if re.match(r'[A-Z]',value):
                 #首字母是大寫
                 if re.search(r'[a-z]',value) and re.search(r'[0-9]',value) and len(value) > 7:
                     return value
                 else:
                     raise ValidationError('密碼格式錯(cuò)誤')
             else:
                 raise ValidationError('密碼首字母必須大寫')

        class Meta:
            model = models.User
            fields = ["username","password"]

分頁

  • 作用:商品列表以及較多數(shù)據(jù)時(shí)使用分頁組件
  • 使用方法
##第一種繼承自PageNumberPagination
    from rest_framework.pagination import PageNumberPagination
    # https://www.baudi.com/?kw=xxx&page=1&pagesize=5
    # 自定義分頁類
    class MyPageNumberPagination(PageNumberPagination):
        #page_size,每頁返回多少條數(shù)據(jù)
        page_size = 5
        #傳遞分頁的參數(shù)
        page_query_param = 'page'
        #傳遞每頁返回多少條數(shù)據(jù)的參數(shù)
        page_size_query_param = 'pagesize'
        #每頁返回?cái)?shù)據(jù)的最大條數(shù)
        max_page_size = 10
        
        def get_paginated_response(self, data):
            ###可選方法斩例,自定義分頁的返回結(jié)果
            ret = {
                'code':1,
                'count':self.page.paginator.count,
                'next':self.get_next_link(),
                'previous':self.get_previous_link(),
                'data':data
            }
            return Response(ret)
#####第二種分頁方式LimitOffsetPagination
    from rest_framework.pagination import LimitOffsetPagination
    # https://www.baudi.com/?kw=xxx&offset=5&limit=5
    class MyLimitOffsetPagination(LimitOffsetPagination):
        #默認(rèn)每頁返回的條數(shù)
        default_limit = 5
        #限制返回條數(shù)的參數(shù)名
        limit_query_param = 'limit'
        #設(shè)置起始的偏移量參數(shù)
        offset_query_param = 'offset'
        #每頁返回?cái)?shù)據(jù)的最大條數(shù)
        max_limit = 10

#####第三種分頁方式CursorPagination
    # 第三種(加密的方式)
    from rest_framework.pagination import CursorPagination
    # http://127.0.0.1:8000/v2/userlist/?cursor=cD03&pagesize=2
    class MyCursorPagination(CursorPagination):
        cursor_query_param = 'cursor'
        page_size = 5
        #排序方式
        ordering = '-id'
        page_size_query_param = 'pagesize'
        max_page_size = 10


視圖

CreateModelMixin: 新增數(shù)據(jù)(POST請求)
DestroyModelMixin: 刪除數(shù)據(jù)(DELETE請求)
UpdateModelMixin: 更新數(shù)據(jù)(PUT請求)
ListModelMixin: 獲取列表數(shù)據(jù) (GET請求)
RetrieveModelMixin: 獲取詳情數(shù)據(jù)(GET請求)
使用以上視圖類的時(shí)候一定要和GenericViewSet配合使用

  • 使用方法
#視圖中的局部使用
class UserList(APIView):
    def get(self,request,*args,**kwargs):
        ret = {
            'code':1,
            'data':None
        }
        # 獲取用戶列表
        queryset = models.User.objects.all()
        #實(shí)例化分頁類
        pg = MyCursorPagination()
        #調(diào)用paginate_queryset進(jìn)行分頁雄人,獲取當(dāng)前分頁數(shù)據(jù)
        pg_data = pg.paginate_queryset(queryset=queryset,request=request,view=self)
        ser = UserSerializer(
                             instance=pg_data,
                             context={'request': request},
                             many=True
                             )
        # return response(ser.data)
        return pg.get_paginated_response(ser.data)
#視圖
    最早使用的是django自帶的視圖類
    from django.views import View
    class UserView(View):
    
        def get(self,request,*args,**kwargs):
            pass
        def post(self,request,*args,**kwargs):
            pass


# 后來使用rest_framework的APIView視圖類(定制性很強(qiáng))
    from rest_framework.views import APIView
    class Register(APIView):
        def get(self,request,*args,**kwargs):
            pass
        def post(self,request,*args,**kwargs):
            pass

#  GenericAPIView視圖的使用(其實(shí)它繼承自APIView,只是在APIView的基礎(chǔ)上
添加了屬性和方法,可以提供給我們調(diào)用)
     from rest_framework.generics import GenericAPIView
     class UserGenericAPIView(GenericAPIView):
         #獲取用戶的列表
         #獲取數(shù)據(jù)庫中表里面的數(shù)據(jù)集
         queryset = models.User.objects.all()
         #設(shè)置序列化的類
         serializer_class = UserSerializer
         #設(shè)置分頁類
         pagination_class = MyPageNumberPagination

         def get(self,request,*args,**kwargs):
             #調(diào)用get_queryset獲取結(jié)果集
             data = self.get_queryset()
             #調(diào)用paginate_queryset獲取當(dāng)前分頁下的數(shù)據(jù)
             pd_data = self.paginate_queryset(queryset=data)
             #調(diào)用get_serializer方法獲取UserSerializer序列化對象
             ser = self.get_serializer(
                 instance=pd_data,many=True,
                 context={'request':request},
             )
             # return Response(ser.data)
             return self.get_paginated_response(ser.data)
# GenericViewSet視圖念赶,路由和請求反射對應(yīng)的方法就會(huì)發(fā)生變化
    (例如get請求的->list)
    from rest_framework.viewsets import GenericViewSet
    class UserGenericAPIView(GenericViewSet):
        #獲取用戶的列表
        #獲取數(shù)據(jù)庫中表里面的數(shù)據(jù)集
        queryset = models.User.objects.all()
        #設(shè)置序列化的類
        serializer_class = UserSerializer
        #設(shè)置分頁類
        pagination_class = MyPageNumberPagination
        
        def list(self,request,*args,**kwargs):
            #調(diào)用get_queryset獲取結(jié)果集
            data = self.get_queryset()
            #調(diào)用paginate_queryset獲取當(dāng)前分頁下的數(shù)據(jù)
            pd_data = self.paginate_queryset(queryset=data)
            #調(diào)用get_serializer方法獲取UserSerializer序列化對象
            ser = self.get_serializer(
                                      instance=pd_data,many=True,
                                      context={'request':request},
                                      )
                                      # return Response(ser.data)
            return self.get_paginated_response(ser.data)
# 路由發(fā)生的變化如下
     url(r"^(?P<version>[v1|v2]+)/userlist/$",UserListView.as_view({'get': 'list','post':'create'})),
     url(r"^(?P<version>[v1|v2]+)/userlist/(?P<pk>\d+)/$",UserListView.as_view(
     {'delete':'destroy','put':'update','get':'retrieve'}))
    
    #### 終極視圖的使用 ####
    from rest_framework.mixins import ListModelMixin,\
        CreateModelMixin,DestroyModelMixin,UpdateModelMixin,\
        RetrieveModelMixin

    # CreateModelMixin: 新增數(shù)據(jù)(POST請求)
    # DestroyModelMixin: 刪除數(shù)據(jù)(DELETE請求)
    # UpdateModelMixin: 更新數(shù)據(jù)(PUT請求)
    # ListModelMixin: 獲取列表數(shù)據(jù) (GET請求)
    # RetrieveModelMixin: 獲取詳情數(shù)據(jù)(GET請求)
    # 使用以上視圖類的時(shí)候一定要和GenericViewSet配合使用

    class UserListView(ListModelMixin,CreateModelMixin,
                       DestroyModelMixin,UpdateModelMixin,
                       RetrieveModelMixin,GenericViewSet):
        #設(shè)置數(shù)據(jù)集
        queryset = models.User.objects.all()
        #設(shè)置序列化類
        serializer_class = UserListSerializer
        #設(shè)置分頁類
        pagination_class = MyPageNumberPagination

路由

  • 使用
#自動(dòng)路由匹配
    from rest_framework.routers import DefaultRouter
    router = DefaultRouter()
    #注冊一個(gè)路由
    router.register(r'userlist',UserListView)
    # ^(?P<version>[v1|v2]+)/ ^userlist/$ [name='user-list']
    # ^(?P<version>[v1|v2]+)/ ^userlist\.(?P<format>[a-z0-9]+)/?$ [name='user-list']
    # ^(?P<version>[v1|v2]+)/ ^userlist/(?P<pk>[^/.]+)/$ [name='user-detail']
    # ^(?P<version>[v1|v2]+)/ ^userlist/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='user-detail']

    urlpatterns = [
        url(r"^(?P<version>[v1|v2]+)/",include(router.urls)),
    ]

渲染器

  • 使用
from rest_framework.renderers import JSONRenderer,\
        BrowsableAPIRenderer,AdminRenderer
    #JSONRenderer:在瀏覽器中只會(huì)返回json數(shù)據(jù)
    #BrowsableAPIRenderer:得到可視化的模版界面
    #AdminRenderer:得到管理員可視化的模版界面
    
    局部使用(視圖中)
    renderer_classes = [JSONRenderer,AdminRenderer]

    全局使用(DRF默認(rèn)已經(jīng)設(shè)置過了础钠,不需要自己設(shè)置)
    'DEFAULT_RENDERER_CLASSES': (
     'rest_framework.renderers.JSONRenderer',
     'rest_framework.renderers.BrowsableAPIRenderer',
    ),

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市叉谜,隨后出現(xiàn)的幾起案子旗吁,更是在濱河造成了極大的恐慌,老刑警劉巖停局,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件很钓,死亡現(xiàn)場離奇詭異香府,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)码倦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門企孩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人袁稽,你說我怎么就攤上這事勿璃。” “怎么了推汽?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵补疑,是天一觀的道長。 經(jīng)常有香客問我民泵,道長癣丧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任栈妆,我火速辦了婚禮胁编,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鳞尔。我一直安慰自己嬉橙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布寥假。 她就那樣靜靜地躺著市框,像睡著了一般。 火紅的嫁衣襯著肌膚如雪糕韧。 梳的紋絲不亂的頭發(fā)上枫振,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機(jī)與錄音萤彩,去河邊找鬼粪滤。 笑死,一個(gè)胖子當(dāng)著我的面吹牛雀扶,可吹牛的內(nèi)容都是我干的杖小。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼愚墓,長吁一口氣:“原來是場噩夢啊……” “哼予权!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起浪册,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤扫腺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后议经,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體斧账,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谴返,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了咧织。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嗓袱。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖习绢,靈堂內(nèi)的尸體忽然破棺而出渠抹,到底是詐尸還是另有隱情,我是刑警寧澤闪萄,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布梧却,位于F島的核電站,受9級(jí)特大地震影響败去,放射性物質(zhì)發(fā)生泄漏放航。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一圆裕、第九天 我趴在偏房一處隱蔽的房頂上張望广鳍。 院中可真熱鬧,春花似錦吓妆、人聲如沸赊时。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽祖秒。三九已至,卻和暖如春舟奠,著一層夾襖步出監(jiān)牢的瞬間竭缝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工沼瘫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留歌馍,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓晕鹊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親暴浦。 傳聞我的和親對象是個(gè)殘疾皇子溅话,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容