Django教程六(中間件)

中間件 Middleware

  • 中間件是 Django 請求/響應(yīng)處理的鉤子框架免糕。它是一個(gè)輕量級的、低級的“插件”系統(tǒng)痒给,用于全局改變 Django 的輸入或輸出说墨。

  • 每個(gè)中間件組件負(fù)責(zé)做一些特定的功能骏全。例如苍柏,Django 包含一個(gè)中間件組件 AuthenticationMiddleware,它使用會(huì)話將用戶與請求關(guān)聯(lián)起來姜贡。

  • 他的文檔解釋了中間件是如何工作的试吁,如何激活中間件,以及如何編寫自己的中間件楼咳。Django 具有一些內(nèi)置的中間件熄捍,你可以直接使用。它們被記錄在 built-in middleware reference 中母怜。

  • 中間件類:

    • 中間件類須繼承自 django.utils.deprecation.MiddlewareMixin
    • 中間件類須實(shí)現(xiàn)下列五個(gè)方法中的一個(gè)或多個(gè):
      • def process_request(self, request): 執(zhí)行視圖之前被調(diào)用余耽,在每個(gè)請求上調(diào)用,返回None或HttpResponse對象

      • def process_view(self, request, callback, callback_args, callback_kwargs): 調(diào)用視圖之前被調(diào)用苹熏,在每個(gè)請求上調(diào)用碟贾,返回None或HttpResponse對象

      • def process_response(self, request, response): 所有響應(yīng)返回瀏覽器之前被調(diào)用,在每個(gè)請求上調(diào)用轨域,返回HttpResponse對象

      • def process_exception(self, request, exception): 當(dāng)處理過程中拋出異常時(shí)調(diào)用袱耽,返回一個(gè)HttpResponse對象

      • def process_template_response(self, request, response): 在視圖剛好執(zhí)行完畢之后被調(diào)用,在每個(gè)請求上調(diào)用干发,返回實(shí)現(xiàn)了render方法的響應(yīng)對象

    • 注: 中間件中的大多數(shù)方法在返回None時(shí)表示忽略當(dāng)前操作進(jìn)入下一項(xiàng)事件朱巨,當(dāng)返回HttpResponese對象時(shí)表示此請求結(jié)果,直接返回給客戶端
  • 編寫中間件類:

# file : middleware/mymiddleware.py
from django.http import HttpResponse, Http404
from django.utils.deprecation import MiddlewareMixin

class MyMiddleWare(MiddlewareMixin):
    def process_request(self, request):
        print("中間件方法 process_request 被調(diào)用")

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("中間件方法 process_view 被調(diào)用")

    def process_response(self, request, response):
        print("中間件方法 process_response 被調(diào)用")
        return response

    def process_exception(self, request, exception):
        print("中間件方法 process_exception 被調(diào)用")

    def process_template_response(self, request, response):
        print("中間件方法 process_template_response 被調(diào)用")
        return response
  • 注冊中間件:
# file : settings.py
MIDDLEWARE = [
    ...
    'middleware.mymiddleware.MyMiddleWare',
]
  • 中間件的執(zhí)行過程


    middleware.jpeg
  • 練習(xí)
    • 用中間件實(shí)現(xiàn)強(qiáng)制某個(gè)IP地址只能向/test 發(fā)送一次GET請求
    • 提示:
      • request.META['REMOTE_ADDR'] 可以得到遠(yuǎn)程客戶端的IP地址
      • request.path_info 可以得到客戶端訪問的GET請求路由信息
    • 答案:
      from django.http import HttpResponse, Http404
      from django.utils.deprecation import MiddlewareMixin
      import re
      class VisitLimit(MiddlewareMixin):
          '''此中間件限制一個(gè)IP地址對應(yīng)的訪問/user/login 的次數(shù)不能改過10次,超過后禁止使用'''
          visit_times = {}  # 此字典用于記錄客戶端IP地址有訪問次數(shù)
          def process_request(self, request):
              ip_address = request.META['REMOTE_ADDR']  # 得到IP地址
              if not re.match('^/test', request.path_info):
                  return
              times = self.visit_times.get(ip_address, 0)
              print("IP:", ip_address, '已經(jīng)訪問過', times, '次!:', request.path_info)
              self.visit_times[ip_address] = times + 1
              if times < 5:
                  return
      
              return HttpResponse('你已經(jīng)訪問過' + str(times) + '次枉长,您被禁止了')
      

跨站請求偽造保護(hù) CSRF

  • 跨站請求偽造攻擊
    • 某些惡意網(wǎng)站上包含鏈接冀续、表單按鈕或者JavaScript琼讽,它們會(huì)利用登錄過的用戶在瀏覽器中的認(rèn)證信息試圖在你的網(wǎng)站上完成某些操作,這就是跨站請求偽造洪唐。
  • CSRF
    Cross-Site Request Forgey
    跨     站點(diǎn)   請求    偽裝
    
  • 說明:
    • CSRF中間件和模板標(biāo)簽提供對跨站請求偽造簡單易用的防護(hù)跨琳。
  • 作用:
    • 不讓其它表單提交到此 Django 服務(wù)器
  • 解決方案:
    1. 取消 csrf 驗(yàn)證(不推薦)
      • 刪除 settings.py 中 MIDDLEWARE 中的 django.middleware.csrf.CsrfViewMiddleware 的中間件
    2. 開放驗(yàn)證
      在視圖處理函數(shù)增加: @csrf_protect
      @csrf_protect
      def post_views(request):
          pass
      
    3. 通過驗(yàn)證
      需要在表單中增加一個(gè)標(biāo)簽 
      {% csrf_token %}
      
    • 練習(xí): 項(xiàng)目的注冊部分
      1. 創(chuàng)建一個(gè)數(shù)據(jù)庫 - FruitDay
      2. 創(chuàng)建實(shí)體類 - Users
        1. uphone - varchar(11)
        2. upwd - varchar(50)
        3. uemail - varchar(245)
        4. uname - varchar(20)
        5. isActive - tinyint 默認(rèn)值為1 (True)
      3. 完善注冊 - /register/
        1. 如果是get請求,則去往register.html
        2. 如果是post請求,則處理請求數(shù)據(jù)
          將提交的數(shù)據(jù)保存回?cái)?shù)據(jù)庫

Django中的forms模塊

  • 在Django中提供了 forms 模塊,用forms 模塊可以自動(dòng)生成form內(nèi)部的表單控件,同時(shí)在服務(wù)器端可以用對象的形式接收并操作客戶端表單元素,并能對表單的數(shù)據(jù)進(jìn)行服務(wù)器端驗(yàn)證
  1. forms模塊的作用

    • 通過 forms 模塊,允許將表單與class相結(jié)合桐罕,允許通過 class 生成表單
  2. 使用 forms 模塊的步驟

    1. 在應(yīng)用中創(chuàng)建 forms.py

    2. 導(dǎo)入 django 提供的 forms

      • from django import forms
    3. 創(chuàng)建class,一個(gè)class會(huì)生成一個(gè)表單

      • 定義表單類
            class ClassName(forms.Form):
                ...
        
    4. 在 class 中創(chuàng)建類屬性

      • 一個(gè)類屬性對應(yīng)到表單中是一個(gè)控件
    5. 利用Form 類型的對象自動(dòng)成表單內(nèi)容

    6. 讀取form表單并進(jìn)行驗(yàn)證數(shù)據(jù)

  3. forms.Form 的語法

    • 屬性 = forms.Field類型(參數(shù))
    1. 類型
      class XXX(froms.Form):
          forms.CharField() : 文本框 <input type="text">
          forms.ChoiceField() : 下拉選項(xiàng)框 <select>
          forms.DateField() : 日期框 <input type="date">
          ... ...
      
    2. 參數(shù)
      1. label
        • 控件前的文本
      2. widget
        • 指定小部件
      3. initial
        • 控件的初始值(主要針對文本框類型)
      4. required
        • 是否為必填項(xiàng)脉让,值為(True/False)
  • form 表單示例
    • 手動(dòng)實(shí)現(xiàn)Form 表單

      <form action="/test_form1" method="post">
          <div>
              <label for="id_input_text">請輸入內(nèi)容:</label> <input type="text" name="input_text" id="id_input_text" />
          </div>
          <button type="submit">提交</button>
      </form>
      
    • Django Form 實(shí)現(xiàn) Form 表單

      class MySearch(forms.Form):
          input_text = forms.CharField(label = '請輸入內(nèi)容')
      
  1. 在模板中解析form對象

    1. 方法

      1. 需要自定義 <form>
      2. 表單中的按鈕需要自定義
    2. 解析form對

      在 視圖中創(chuàng)建form對象并發(fā)送到模板中解析.
      ex:
          form = XXXForm()
          return render(request,'xx.html',locals())
      
      1. 手動(dòng)解析
        {% for field in form %}
        field : 表示的是form對象中的每個(gè)屬性(控件)
        {{field.label}} : 表示的是label參數(shù)值
        {{field}} : 表示的就是控件
        {% endfor %}
    3. 自動(dòng)解析

      1. {{form.as_p}}
        將 form 中的每個(gè)屬性(控件/文本)都使用p標(biāo)記包裹起來再顯示
      2. {{form.as_ul}}
        將 form 中的每個(gè)屬性(控件/文本)都使用li標(biāo)記包裹起來再顯示
        注意:必須手動(dòng)提供ol 或 ul 標(biāo)記
        
      3. {{form.as_table}}
        將 form 中的每個(gè)屬性(控件/文本)都使用tr標(biāo)記包裹起來再顯示
        注意:必須手動(dòng)提供table標(biāo)記
        
    • 練習(xí):
      1. 創(chuàng)建一個(gè)注冊Form類 - RegisterForm
        • username - 用戶名稱
        • password - 用戶密碼(文本框)
        • password2 - 重復(fù)用戶密碼(文本框)
        • phonenumber - 用戶年齡(數(shù)字框)
        • email - 電子郵箱
          2.創(chuàng)建 register 路由
        • get 請求 :
          • 創(chuàng)建 RegisterForm 對象并發(fā)送到 模板register.html中顯示
        • post 請求:
          • 接收13-register.html 中的數(shù)據(jù)并輸出
    1. 通過 forms 對象獲取表單數(shù)據(jù)
      1. 通過 forms.Form 子類的構(gòu)造器來接收 post 數(shù)據(jù)
        • form = XXXForm(request.POST)
      2. 必須是 form 通過驗(yàn)證后,才能取值
        • form.is_valid()
          • 返回True:通過驗(yàn)證,可以取值
          • 返回False:暫未通過驗(yàn)證,則不能取值
      3. 通過 form.cleaned_data 字典的屬性接收數(shù)據(jù)
        • form.cleaned_data : dict 類型
  2. Field 內(nèi)置小部件 - widget

    1. 什么是小部件
      • 表示的是生成到網(wǎng)頁上的控件以及一些其他的html屬性
      message=forms.CharField(widget=forms.Textarea)
      upwd=forms.CharField(widget=forms.PasswordInput)
      
    2. 常用的小部件類型
      widget名稱 對應(yīng)和type類值
      TextInput type='text'
      PasswordInput type='password'
      NumberInput type="number"
      EmailInput type="email"
      URLInput type="url"
      HiddenInput type="hidden"
      CheckboxInput type="checkbox"
      CheckboxSelectMultiple type="checkbox"
      RadioSelect type="radio"
      Textarea textarea標(biāo)記
      Select select標(biāo)記
      SelectMultiple select multiple 標(biāo)記
  3. 小部件的使用

    1. 繼承自forms.Form
      1. 基本版
        1. 語法
          屬性 = forms.CharField() #無預(yù)選值使用
              text,password,email,url,textarea,checkbox
          屬性 = forms.ChoiceField() #有預(yù)選值使用
              checkbox,radio,select
          
          屬性 = forms.CharField(
              label='xxx',
              widget=forms.小部件類型
          )
          
        2. 示例:
          upwd = forms.CharField(
              label='用戶密碼',
              widget=forms.PasswordInput
          )
          
          message = forms.CharField(
              label='評論內(nèi)容',
              widget=forms.Textarea
          )
          

Django之form表單驗(yàn)證

  • django form 提供表單和字段驗(yàn)證

  • 當(dāng)在創(chuàng)建有不同的多個(gè)表單需要提交的網(wǎng)站時(shí),用表單驗(yàn)證比較方便驗(yàn)證的封裝

  • 當(dāng)調(diào)用form.is_valid() 返回True表示當(dāng)前表單合法功炮,當(dāng)返回False說明表單驗(yàn)證出現(xiàn)問題

  • 驗(yàn)證步驟:

    1. 先對form.XXXField() 參數(shù)值進(jìn)行驗(yàn)證溅潜,比如:min_length,max_length, validators=[...],如果不符合form.is_valid()返回False
    2. 對各自from.clean_zzz屬性名(self): 方法對相應(yīng)屬性進(jìn)行驗(yàn)證,如果驗(yàn)證失敗form.is_valid()返回False
    3. 調(diào)胳form.clean(self): 對表單的整體結(jié)構(gòu)進(jìn)行驗(yàn)證,如果驗(yàn)證失敗form.is_valid()返回False
    4. 以上驗(yàn)證都成功 form.is_valid()返回True
  • 驗(yàn)證方法:

    • validators = [驗(yàn)證函數(shù)1, 驗(yàn)證函數(shù)1]
      • 驗(yàn)證函數(shù)驗(yàn)證失敗拋出forms.ValidationError
      • 驗(yàn)證成功返回None
    • def clean_xxx屬性(self):
      • 驗(yàn)證失敗必須拋出forms.ValidationError
      • 驗(yàn)證成功必須返回xxx屬性的值
    • def clean(self):
      • 驗(yàn)證失敗必須拋出forms.ValidationError
      • 驗(yàn)證成功必須返回 self.cleaned_data
  • 文檔參見https://docs.djangoproject.com/en/1.11/ref/forms/validation/

  • 驗(yàn)證示例

from django import forms
import re

mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
def mobile_validate(value):
    if not mobile_re.match(value):
        raise forms.ValidationError('手機(jī)號碼格式錯(cuò)誤')

class RegisterForm(forms.Form):
    username = forms.CharField(label='用戶名')
    password = forms.CharField(label='請輸入密碼', widget=forms.PasswordInput)
    password2 = forms.CharField(label='再次輸入新密碼', widget=forms.PasswordInput)
    mobile = forms.CharField(label='電話號碼', validators=[mobile_validate])

    def clean(self):
        pwd1 = self.cleaned_data['password']
        pwd2 = self.cleaned_data['password2']
        if pwd1 != pwd2:
            raise forms.ValidationError('兩次密碼不一致!')
        return self.cleaned_data  # 必須返回cleaned_data

    def clean_username(self):
        username = self.cleaned_data['username']
        if len(username) < 6:
            raise forms.ValidationError("用戶名太短")
        return username
  • 練習(xí)薪伏,寫一個(gè)RegisterForm表單類型,要求如下四個(gè)屬性:
    • username - 用戶名稱
      • 用戶名只能包含[a-zA-Z_0_9]范圍內(nèi)的5~30個(gè)英文字符
    • password - 用戶密碼(文本框)
      • 任意字符滚澜,不能少于6個(gè)字符
    • password2 - 重復(fù)用戶密碼(文本框)
      • 任意字符,不能少于6個(gè)字符且必須與 password一致
    • phonenumber - 用戶年齡(數(shù)字框)
      • 必須符合r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$'正則表達(dá)式

分頁

  • 分頁是指在web頁面有大量數(shù)據(jù)需要顯示時(shí)嫁怀,當(dāng)一頁的內(nèi)容太多不利于閱讀和不利于數(shù)據(jù)提取的情況下设捐,可以分為多頁進(jìn)行顯示。
  • Django提供了一些類來幫助你管理分頁的數(shù)據(jù) — 也就是說塘淑,數(shù)據(jù)被分在不同頁面中萝招,并帶有“上一頁/下一頁”鏈接。
  • 這些類位于django/core/paginator.py中存捺。

Paginator對象

  • 對象的構(gòu)造方法

    • Paginator(object_list, per_page)
    • 參數(shù)
      • object_list 對象列表
      • per_page 每頁數(shù)據(jù)個(gè)數(shù)
    • 返回值:
      • 分頁對象
  • Paginator屬性

    • count:對象總數(shù)
    • num_pages:頁面總數(shù)
    • page_range:從1開始的range對象, 用于記錄當(dāng)前面碼數(shù)
    • per_page 每頁個(gè)數(shù)
  • Paginator方法

    • Paginator.page(number)
      • 參數(shù) number為頁碼信息(從1開始)
      • 返回當(dāng)前number頁對應(yīng)的頁信息
      • 如果提供的頁碼不存在槐沼,拋出InvalidPage異常
  • Paginator異常exception

    • InvalidPage:當(dāng)向page()傳入一個(gè)無效的頁碼時(shí)拋出
    • PageNotAnInteger:當(dāng)向page()傳入一個(gè)不是整數(shù)的值時(shí)拋出
    • EmptyPage:當(dāng)向page()提供一個(gè)有效值,但是那個(gè)頁面上沒有任何對象時(shí)拋出

Page對象

  • 創(chuàng)建對象
    Paginator對象的page()方法返回Page對象捌治,不需要手動(dòng)構(gòu)造

  • Page對象屬性

    • object_list:當(dāng)前頁上所有對象的列表
    • number:當(dāng)前頁的序號岗钩,從1開始
    • paginator:當(dāng)前page對象相關(guān)的Paginator對象
  • Page對象方法

    • has_next():如果有下一頁返回True
    • has_previous():如果有上一頁返回True
    • has_other_pages():如果有上一頁或下一頁返回True
    • next_page_number():返回下一頁的頁碼,如果下一頁不存在肖油,拋出InvalidPage異常
    • previous_page_number():返回上一頁的頁碼兼吓,如果上一頁不存在,拋出InvalidPage異常
    • len():返回當(dāng)前頁面對象的個(gè)數(shù)
  • 說明:

    • Page 對象是可迭代對象,可以用 for 語句來 訪問當(dāng)前頁面中的每個(gè)對象
  • 參考文檔https://docs.djangoproject.com/en/1.11/topics/pagination/

  • 分頁示例:
    • 視圖函數(shù)
    def book(request):
        bks = models.Book.objects.all()
        paginator = Paginator(bks, 10)
        print('當(dāng)前對象的總個(gè)數(shù)是:', paginator.count)
        print('當(dāng)前對象的面碼范圍是:', paginator.page_range)
        print('總頁數(shù)是:', paginator.num_pages)
        print('每頁最大個(gè)數(shù):', paginator.per_page)
    
        cur_page = request.GET.get('page', 1)  # 得到默認(rèn)的當(dāng)前頁
        page = paginator.page(cur_page)
        return render(request, 'bookstore/book.html', locals())
    
    • 模板設(shè)計(jì)
    <html>
    <head>
        <title>分頁顯示</title>
    </head>
    <body>
    {% for b in page %}
        <div>{{ b.title }}</div>
    {% endfor %}
    
    {# 分頁功能 #}
    {# 上一頁功能 #}
    {% if page.has_previous %}
    <a href="{% url "book" %}?page={{ page.previous_page_number }}">上一頁</a>
    {% else %}
    上一頁
    {% endif %}
    
    {% for p in paginator.page_range %}
        {% if p == page.number %}
            {{ p }}
        {% else %}
            <a href="{% url "book" %}?page={{ p }}">{{ p }}</a>
        {% endif %}
    {% endfor %}
    
    {#下一頁功能#}
    {% if page.has_next %}
    <a href="{% url "book" %}?page={{ page.next_page_number }}">上一頁</a>
    {% else %}
    上一頁
    {% endif %}
    總頁數(shù): {{ page.len }}
    </body>
    </html>
    
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末森枪,一起剝皮案震驚了整個(gè)濱河市视搏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疲恢,老刑警劉巖凶朗,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異显拳,居然都是意外死亡棚愤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宛畦,“玉大人瘸洛,你說我怎么就攤上這事〈魏停” “怎么了反肋?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長踏施。 經(jīng)常有香客問我石蔗,道長,這世上最難降的妖魔是什么畅形? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任养距,我火速辦了婚禮,結(jié)果婚禮上日熬,老公的妹妹穿的比我還像新娘棍厌。我一直安慰自己,他們只是感情好竖席,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布耘纱。 她就那樣靜靜地躺著,像睡著了一般毕荐。 火紅的嫁衣襯著肌膚如雪束析。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天东跪,我揣著相機(jī)與錄音畸陡,去河邊找鬼。 笑死虽填,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的曹动。 我是一名探鬼主播斋日,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼墓陈!你這毒婦竟也來了恶守?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤贡必,失蹤者是張志新(化名)和其女友劉穎兔港,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體仔拟,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡衫樊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片科侈。...
    茶點(diǎn)故事閱讀 40,488評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡载佳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出臀栈,到底是詐尸還是另有隱情蔫慧,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布权薯,位于F島的核電站姑躲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏盟蚣。R本人自食惡果不足惜肋联,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望刁俭。 院中可真熱鬧橄仍,春花似錦、人聲如沸牍戚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽如孝。三九已至宪哩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間第晰,已是汗流浹背锁孟。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留茁瘦,地道東北人品抽。 一個(gè)月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像甜熔,于是被迫代替她去往敵國和親圆恤。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評論 2 359

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