摘要:學(xué)習(xí)小組是由我發(fā)起的一個(gè)促進(jìn)新手互相學(xué)習(xí)互相幫助的組織。當(dāng)然如果你不喜歡英文,可以看我們的中文翻譯版本入門(mén)教程中文翻譯版。如果模板文件中有如下代碼那么渲染時(shí)就會(huì)循環(huán)渲染篇文章,并且也會(huì)被存儲(chǔ)在數(shù)據(jù)庫(kù)中文章的標(biāo)題取代。
本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn): django 博客開(kāi)發(fā)入門(mén)教程。
本節(jié)是 Django Blog 項(xiàng)目的開(kāi)篇,是?Django 學(xué)習(xí)小組的集體學(xué)習(xí)成果。Django 學(xué)習(xí)小組是由我發(fā)起的一個(gè)促進(jìn) Django 新手互相學(xué)習(xí)、互相幫助的組織。小組在一邊學(xué)習(xí) Django 的同時(shí)將一起完成三個(gè)項(xiàng)目:
一個(gè)簡(jiǎn)單 Django Blog,用于發(fā)布小組每周的學(xué)習(xí)和開(kāi)發(fā)文檔
Django 中國(guó)社區(qū),為國(guó)內(nèi)的 Django 開(kāi)發(fā)者們提供一個(gè)長(zhǎng)期維護(hù)的 Django 社區(qū),聚集全國(guó)的 Django 開(kāi)發(fā)者到這個(gè)社區(qū)上來(lái)
Django 問(wèn)答社區(qū), 類(lèi)似于 segmentfault 和 stackoverflow 但更加專(zhuān)注(只專(zhuān)注于 Django 開(kāi)發(fā)的問(wèn)題)的問(wèn)答社區(qū)
目前小組正在完成第一個(gè)項(xiàng)目,本文即是該項(xiàng)目第一周的相關(guān)文檔。
更多的信息請(qǐng)關(guān)注我們的?github 組織首頁(yè),本教程項(xiàng)目的相關(guān)源代碼也已上傳到 github 上。
同時(shí),你也可以加入我們的郵件列表?django_study@groups.163.com?,隨時(shí)關(guān)注我們的動(dòng)態(tài),我們會(huì)將每周的詳細(xì)開(kāi)發(fā)文檔和代碼通過(guò)郵件列表發(fā)出。
如有任何建議,歡迎提 Issue,歡迎fork,pull requests,當(dāng)然也別忘了 Star 哦!
每周更新,敬請(qǐng)關(guān)注
django 的開(kāi)發(fā)環(huán)境搭建以及如何創(chuàng)建工程在網(wǎng)上有大量的博客和教程介紹,在此不再重復(fù)說(shuō)明。但我建議最好的參考資料還是Django官方的入門(mén) Tutorials ,即官方文檔的 First steps 部分的六個(gè) Parts。當(dāng)然如果你不喜歡英文,可以看我們的中文翻譯版本:Django 入門(mén)教程中文翻譯版。
要開(kāi)始 Django 開(kāi)發(fā),你需要從中掌握以下知識(shí):
如何創(chuàng)建 Django 工程,并了解 Django 默認(rèn)的工程目錄結(jié)構(gòu)
如何創(chuàng)建 Django APP
理解 Django 的MTV 模式,學(xué)會(huì)編寫(xiě) Model、View、Template
Django 如何處理靜態(tài)文件,即各種 CSS,JS,以及圖片文件等
我們強(qiáng)烈建議你在閱讀完上面的教程以掌握 Django 開(kāi)發(fā)所需的最基本概念后開(kāi)始本項(xiàng)目的學(xué)習(xí)
Django應(yīng)用是如何工作的?先看一張流程圖,再來(lái)逐步講解其過(guò)程:
1:用戶(hù)通過(guò)瀏覽器輸入相應(yīng)的 URL 發(fā)起 HTTP 請(qǐng)求(一般是 GET/POST)
2:Django 接受到請(qǐng)求,檢測(cè) urls.py 文件,找到和用戶(hù)輸入的 URL 相匹配的項(xiàng),并調(diào)用該 URL 對(duì)應(yīng)的視圖函數(shù)(view),例如,通常來(lái)說(shuō) urls.py 文件里的代碼是這樣的:
url(r"^homepage/$", views.home_page)
則當(dāng)用戶(hù)輸入的 URL 為 www.某個(gè)網(wǎng)址.com/homepage 時(shí),django 檢測(cè)到該 URL 與上面的代碼 匹配,于是調(diào)用后面的 views.home_page 視圖函數(shù),把相應(yīng)的請(qǐng)求交給該視圖函數(shù)處理。
3:視圖函數(shù)被調(diào)用后,可能會(huì)訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)(Model)去查詢(xún)用戶(hù)想要請(qǐng)求的數(shù)據(jù),并加載模板文件(Template),渲染完數(shù)據(jù)后打包成 HttpResponse 返回給瀏覽器(Http協(xié)議)
大致工作流程就是這樣,從流程可以看出,我們需要做的就是:
編寫(xiě)相應(yīng)的 url
編寫(xiě)數(shù)據(jù)庫(kù)(Model)
編寫(xiě)處理 Http 請(qǐng)求的視圖函數(shù)(View)
編寫(xiě)需要渲染的模板(Template)
這就是 Django 開(kāi)發(fā)的最主要工作,下面遵循這樣的開(kāi)發(fā)流程開(kāi)始編寫(xiě)我們的 Blog程序吧。
編寫(xiě) ModelModel 對(duì)應(yīng)數(shù)據(jù)庫(kù),我們編寫(xiě)的是一個(gè) Blog 應(yīng)用,因此數(shù)據(jù)庫(kù)中應(yīng)該存放 Blog 下的文章(Aticle),文章由標(biāo)題(title)、正文(body)、發(fā)布時(shí)間(publised_time)等組成。先看 django 是如何定義數(shù)據(jù)庫(kù)的,之后再逐行解釋代碼(假設(shè)你已經(jīng)對(duì) django 的工程目錄結(jié)構(gòu)了解了,我們一般把 Model 定義在 models.py 文件中):
models.py from django.db import models class Article(models.Model): STATUS_CHOICES = ( ("d", "Draft"), ("p", "Published"), ) title = models.CharField("標(biāo)題", max_length=70) body = models.TextField("正文") created_time = models.DateTimeField("創(chuàng)建時(shí)間", auto_now_add=True) last_modified_time = models.DateTimeField("修改時(shí)間", auto_now=True) status = models.CharField("文章?tīng)顟B(tài)", max_length=1, choices=STATUS_CHOICES) abstract = models.CharField("摘要", max_length=54, blank=True, null=True, help_text="可選,如若為空將摘取正文的前54個(gè)字符") views = models.PositiveIntegerField("瀏覽量", default=0) likes = models.PositiveIntegerField("點(diǎn)贊數(shù)", default=0) topped = models.BooleanField("置頂", default=False) category = models.ForeignKey("Category", verbose_name="分類(lèi)", null=True, on_delete=models.SET_NULL) def __str__(self): return self.title class Meta: ordering = ["-last_modified_time"] class Category(models.Model): name = models.CharField("類(lèi)名", max_length=20) created_time = models.DateTimeField("創(chuàng)建時(shí)間", auto_now_add=True) last_modified_time = models.DateTimeField("修改時(shí)間", auto_now=True) def __str__(self): return self.name
逐行解釋?zhuān)?/p>
from django.db import models # 和 model 相關(guān)的一些API定義在 django.db.models 模塊中 class Article(models.Model): """ 所有的 model 必須繼承自django.db.models 類(lèi) Aticle 即表示 Blog 的文章,一個(gè)類(lèi)被 diango 映射成數(shù)據(jù)庫(kù)中對(duì)應(yīng)的一個(gè)表,表名即類(lèi)名 類(lèi)的屬性(field),比如下面的 title、body 等對(duì)應(yīng)著數(shù)據(jù)庫(kù)表的屬性列 """ STATUS_CHOICES = ( ("d", "Draft"), ("p", "Published"), ) # 在 status 時(shí)說(shuō)明 title = models.CharField("標(biāo)題", max_length=70) # 文章標(biāo)題,CharField 表示對(duì)應(yīng)數(shù)據(jù)庫(kù)中表的列是用來(lái)存字符串的,"標(biāo)題"是一個(gè)位置參數(shù) #(verbose_name),主要用于 django 的后臺(tái)系統(tǒng),不多做介紹。max_length 表示能存儲(chǔ)的字符串 # 的最大長(zhǎng)度 body = models.TextField("正文") # 文章正文,TextField 用來(lái)存儲(chǔ)大文本字符 created_time = models.DateTimeField("創(chuàng)建時(shí)間", auto_now_add=True) # 文章創(chuàng)建時(shí)間,DateTimeField用于存儲(chǔ)時(shí)間,設(shè)定auto_now_add參數(shù)為真,則在文章被創(chuàng)建時(shí)會(huì)自動(dòng)添加創(chuàng)建時(shí)間 last_modified_time = models.DateTimeField("修改時(shí)間", auto_now=True) # 文章最后一次編輯時(shí)間,auto_now=True表示每次修改文章時(shí)自動(dòng)添加修改的時(shí)間 status = models.CharField("文章?tīng)顟B(tài)", max_length=1, choices=STATUS_CHOICES) # STATUS_CHOICES,field 的 choices 參數(shù)需要的值,choices選項(xiàng)會(huì)使該field在被渲染成form時(shí)被渲染為一個(gè)select組件,這里我定義了兩個(gè)狀態(tài),一個(gè)是Draft(草稿),一個(gè)是Published(已發(fā)布),select組件會(huì)有兩個(gè)選項(xiàng):Draft 和 Published。但是存儲(chǔ)在數(shù)據(jù)庫(kù)中的值分別是"d"和"p",這就是 choices的作用。 abstract = models.CharField("摘要", max_length=54, blank=True, null=True, help_text="可選,如若為空將摘取正文的前54個(gè)字符") # 文章摘要,help_text 在該 field 被渲染成 form 是顯示幫助信息 views = models.PositiveIntegerField("瀏覽量", default=0) # 閱覽量,PositiveIntegerField存儲(chǔ)非負(fù)整數(shù) likes = models.PositiveIntegerField("點(diǎn)贊數(shù)", default=0) # 點(diǎn)贊數(shù) topped = models.BooleanField("置頂", default=False) # 是否置頂,BooleanField 存儲(chǔ)布爾值(True或者False),默認(rèn)(default)為False category = models.ForeignKey("Category", verbose_name="分類(lèi)", null=True, on_delete=models.SET_NULL) # 文章的分類(lèi),F(xiàn)oreignKey即數(shù)據(jù)庫(kù)中的外鍵。外鍵的定義是:如果數(shù)據(jù)庫(kù)中某個(gè)表的列的值是另外一個(gè)表的主鍵。外鍵定義了一個(gè)一對(duì)多的關(guān)系,這里即一篇文章對(duì)應(yīng)一個(gè)分類(lèi),而一個(gè)分類(lèi)下可能有多篇 文章。詳情參考django官方文檔關(guān)于ForeinKey的說(shuō)明,on_delete=models.SET_NULL表示刪除某個(gè)分類(lèi)(category)后該分類(lèi)下所有的Article的外鍵設(shè)為null(空) def __str__(self): # 主要用于交互解釋器顯示表示該類(lèi)的字符串 return self.title class Meta: # Meta 包含一系列選項(xiàng),這里的 ordering 表示排序,- 號(hào)表示逆序。即當(dāng)從數(shù)據(jù)庫(kù)中取出文章時(shí),其是按文章最后一次修改時(shí)間逆序排列的。 ordering = ["-last_modified_time"] class Category(models.Model): """ 另外一個(gè)表,存儲(chǔ)文章的分類(lèi)信息 """ name = models.CharField("類(lèi)名", max_length=20) created_time = models.DateTimeField("創(chuàng)建時(shí)間", auto_now_add=True) last_modified_time = models.DateTimeField("修改時(shí)間", auto_now=True) def __str__(self): return self.name
由上可見(jiàn),設(shè)計(jì)數(shù)據(jù)庫(kù)結(jié)構(gòu)就是編寫(xiě) models,數(shù)據(jù)庫(kù)中每一個(gè)實(shí)體對(duì)應(yīng)的表在 django 中對(duì)用著 models.py 中的一個(gè)類(lèi),類(lèi)的屬性對(duì)應(yīng)著數(shù)據(jù)庫(kù)表的屬性列。
model 定義完畢后,運(yùn)行以下命令即可生成相應(yīng)的數(shù)據(jù)庫(kù):
python manage.py makemigrations
python manage.py migrate
你可以打開(kāi)相應(yīng)的數(shù)據(jù)庫(kù)文件看看里面生成的表結(jié)構(gòu),加深理解。
其中以上的代碼中涉及到一些 django 相關(guān)的概念,分別給出以下參考資料供學(xué)習(xí):
Django 模型層(model)的概論:官方文檔、中文翻譯文檔
類(lèi)中各屬性(field):官方文檔對(duì) django 提供的各 field 的介紹、相應(yīng)的中文文檔
ForeinKey(一對(duì)多),還有 ManyToMany(多對(duì)多)、OneToOne(一對(duì)一)的介紹:官方文檔對(duì)外關(guān)系的介紹
編寫(xiě) View上面已經(jīng)介紹了 django 應(yīng)用的工作流程,數(shù)據(jù)庫(kù)建立完畢后需要編寫(xiě)視圖函數(shù)(view)來(lái)處理 Http 請(qǐng)求。同樣先來(lái)看 django 的 view 代碼是如何寫(xiě)的,然后我們?cè)僦鹦薪忉尅?/p>
我們現(xiàn)在要設(shè)計(jì)的是一個(gè)首頁(yè)的視圖函數(shù),即用戶(hù)進(jìn)入我們的 Blog 首頁(yè)后,我們需要把數(shù)據(jù)庫(kù)中存儲(chǔ)的文章的相關(guān)信息取出來(lái)展示給用戶(hù)看:
views.py from django.views.generic.list import ListView from blog.models import Article, Category import markdown2 class IndexView(ListView): template_name = "blog/index.html" context_object_name = "article_list" def get_queryset(self): article_list = Article.objects.filter(status="p") for article in article_list: article.body = markdown2.markdown(article.body, ) return article_list def get_context_data(self, **kwargs): kwargs["category_list"] = Category.objects.all().order_by("name") return super(IndexView, self).get_context_data(**kwargs)
逐行解釋?zhuān)?/p>
from blog.models import Article from blog.models import Category from django.views.generic import ListView import markdown2 class IndexView(ListView): """ 首頁(yè)視圖,繼承自L(fǎng)istVIew,用于展示從數(shù)據(jù)庫(kù)中獲取的文章列表 """ template_name = "blog/index.html" # template_name屬性用于指定使用哪個(gè)模板進(jìn)行渲染 context_object_name = "article_list" # context_object_name屬性用于給上下文變量取名(在模板中使用該名字) def get_queryset(self): """ 過(guò)濾數(shù)據(jù),獲取所有已發(fā)布文章,并且將內(nèi)容轉(zhuǎn)成markdown形式 """ article_list = Article.objects.filter(status="p") # 獲取數(shù)據(jù)庫(kù)中的所有已發(fā)布的文章,即filter(過(guò)濾)狀態(tài)為"p"(已發(fā)布)的文章。 for article in article_list: article.body = markdown2.markdown(article.body, ) # 將markdown標(biāo)記的文本轉(zhuǎn)為html文本 return article_list def get_context_data(self, **kwargs): # 增加額外的數(shù)據(jù),這里返回一個(gè)文章分類(lèi),以字典的形式 kwargs["category_list"] = Category.objects.all().order_by("name") return super(IndexView, self).get_context_data(**kwargs)
可能覺(jué)得奇怪的是既然是視圖函數(shù)為什么不是用 def 來(lái)定義,而是寫(xiě)成一個(gè)類(lèi)?這里涉及到 django 的關(guān)于類(lèi)的通用視圖的概念:參考類(lèi)的通用視圖。我們通過(guò)調(diào)用 as_view 方法會(huì)將該類(lèi)視圖轉(zhuǎn)為一般的視圖,這在 url 部分會(huì)介紹。
這樣,這個(gè)視圖的工作流程就是首先接受來(lái)自用戶(hù)的 Http 請(qǐng)求,然后從數(shù)據(jù)庫(kù)中獲取到已經(jīng)發(fā)布的文章列表:article_list = Article.objects.filter(status="p"),并轉(zhuǎn)換 markdown 語(yǔ)法標(biāo)記,再加載模板文件:template_name = "blog/index.html",將模板中的變量用相應(yīng)的數(shù)據(jù)庫(kù)中的數(shù)據(jù)庫(kù)替換后返回給瀏覽器,這樣,用戶(hù)就看到了從數(shù)據(jù)庫(kù)中被取出然后被渲染后的文章列表了。
編寫(xiě) Templatetemplate 稍微麻煩一點(diǎn),因?yàn)樯婕暗?html 的相關(guān)知識(shí),如果你沒(méi)有學(xué)過(guò) html ,可能會(huì)有些看不懂,因此推薦學(xué)習(xí)一下,這里有很棒的教程:w3school 的 html 教程供學(xué)習(xí)使用。這里只介紹一點(diǎn)點(diǎn)本項(xiàng)目涉及的模板相關(guān)知識(shí),其實(shí) django 文檔的入門(mén)教程的六個(gè) parts 中涵蓋的點(diǎn)已經(jīng)足以對(duì)付此簡(jiǎn)單的 Blog 項(xiàng)目了。
模板標(biāo)簽,用{% %} 表示,一些常用的有{% for %}循環(huán)標(biāo)簽,{% if %}判斷標(biāo)簽等。
模板變量,用{{ variable }}表示,模板渲染是這些變量會(huì)被數(shù)據(jù)庫(kù)中相應(yīng)的值代替,例如article_list = Article.objects.filter(status="p"),從數(shù)據(jù)庫(kù)中取出了已發(fā)布的文章列表,賦給了 article_list 變量。如果模板文件中有如下代碼:
{% for article in article_list %} {{article.title}}
那么渲染時(shí)就會(huì)循環(huán)渲染 n 篇文章,并且 {{article.title}} 也會(huì)被存儲(chǔ)在數(shù)據(jù)庫(kù)中文章的標(biāo)題取代。
更多詳細(xì)的資料,請(qǐng)參考官方文檔關(guān)于 template 的介紹,或者中文文檔
編寫(xiě) URL寫(xiě)好了數(shù)據(jù)庫(kù)、視圖和模板,現(xiàn)在就是當(dāng)用戶(hù)在瀏覽器輸入 url 訪(fǎng)問(wèn)我們的 Blog 時(shí)要告訴 django 哪個(gè) url 的請(qǐng)求對(duì)應(yīng)哪個(gè)視圖函數(shù)來(lái)處理,通過(guò) urls.py 來(lái)指定:
urls.py urlpatterns = [ ... url(r"^blog/", views.IndexView.as_view()), # 首頁(yè)調(diào)用IndexView ... ]
至此,Blog 應(yīng)用的首頁(yè)算是完成了,當(dāng)用戶(hù)訪(fǎng)問(wèn)我們的主頁(yè)就可以看到文章列表了:
接下來(lái)做什么?至此,我們完成了博客的首頁(yè)以展示文章列表的功能,接下來(lái)我們會(huì)為我們的 Blog 添加詳情頁(yè)面和分類(lèi)頁(yè)面功能,即用戶(hù)點(diǎn)擊文章標(biāo)題或者閱讀原文后進(jìn)入文章的詳細(xì)頁(yè)面,點(diǎn)擊分類(lèi)則展示該分類(lèi)下的全部文章列表。敬請(qǐng)期待我們下一周的教程。如果你希望為你的 Blog 添加其他更加獨(dú)特的功能,也請(qǐng)隨時(shí)告訴我們。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/37949.html
摘要:本節(jié)接上周的文檔學(xué)習(xí)小組博客開(kāi)發(fā)實(shí)戰(zhàn)第一周教程編寫(xiě)博客的首頁(yè)面,我們繼續(xù)給博客添加功能,以及改善前面不合理的部分。返回該視圖要顯示的對(duì)象。目前小組正在完成第一個(gè)項(xiàng)目,本文即是該項(xiàng)目第二周的相關(guān)文檔。 本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn): django 博客開(kāi)發(fā)入門(mén)教程。 上周我們完成了博客的 Model 部分,以及 Blog 的首頁(yè)視圖 IndexView。 本節(jié)接上周的文檔 Djan...
摘要:本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn)博客開(kāi)發(fā)入門(mén)教程。我們的評(píng)論表單放在中,評(píng)論成功后返回到原始提交頁(yè)面。學(xué)習(xí)小組簡(jiǎn)介學(xué)習(xí)小組是一個(gè)促進(jìn)新手互相學(xué)習(xí)互相幫助的組織。 本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn): django 博客開(kāi)發(fā)入門(mén)教程。 通過(guò)前四周的時(shí)間我們開(kāi)發(fā)了一個(gè)簡(jiǎn)單的個(gè)人 Blog,前幾期教程地址: 第一周:Django 學(xué)習(xí)小組:博客開(kāi)發(fā)實(shí)戰(zhàn)第一周教程 —— 編寫(xiě)博客的 Mode...
摘要:本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn)博客開(kāi)發(fā)入門(mén)教程。我們的評(píng)論表單放在中,評(píng)論成功后返回到原始提交頁(yè)面。學(xué)習(xí)小組簡(jiǎn)介學(xué)習(xí)小組是一個(gè)促進(jìn)新手互相學(xué)習(xí)互相幫助的組織。 本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn): django 博客開(kāi)發(fā)入門(mén)教程。 通過(guò)前四周的時(shí)間我們開(kāi)發(fā)了一個(gè)簡(jiǎn)單的個(gè)人 Blog,前幾期教程地址: 第一周:Django 學(xué)習(xí)小組:博客開(kāi)發(fā)實(shí)戰(zhàn)第一周教程 —— 編寫(xiě)博客的 Mode...
摘要:本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn)博客開(kāi)發(fā)入門(mén)教程。表示降序排列,默認(rèn)是升序排列。學(xué)習(xí)小組簡(jiǎn)介學(xué)習(xí)小組是一個(gè)促進(jìn)新手互相學(xué)習(xí)互相幫助的組織。我們會(huì)將每周的詳細(xì)開(kāi)發(fā)文檔和代碼通過(guò)郵件列表發(fā)出。 本教程內(nèi)容已過(guò)時(shí),更新版教程請(qǐng)?jiān)L問(wèn): django 博客開(kāi)發(fā)入門(mén)教程。 通過(guò)前四周的時(shí)間我們開(kāi)發(fā)了一個(gè)簡(jiǎn)單的個(gè)人 Blog,教程地址: 第一周:Django 學(xué)習(xí)小組:博客開(kāi)發(fā)實(shí)戰(zhàn)第一周教程 ——...
摘要:本教程首先介紹兩個(gè)項(xiàng)目中遇到的通用視圖和。語(yǔ)句的作用是添加了到上下文中,還要把默認(rèn)的一些上下文變量也返回給視圖函數(shù),以便其后續(xù)處理。 通過(guò)三周的時(shí)間我們開(kāi)發(fā)了一個(gè)簡(jiǎn)單的個(gè)人 Blog,教程地址: 第一周:Django 學(xué)習(xí)小組:博客開(kāi)發(fā)實(shí)戰(zhàn)第一周教程 —— 編寫(xiě)博客的 Model 和首頁(yè)面 第二周:Django 學(xué)習(xí)小組:博客開(kāi)發(fā)實(shí)戰(zhàn)第二周教程 —— 博客詳情頁(yè)面和分類(lèi)頁(yè)面 第三周:D...
閱讀 655·2021-09-24 09:48
閱讀 2499·2021-08-26 14:14
閱讀 524·2019-08-30 13:08
閱讀 1450·2019-08-29 15:22
閱讀 3084·2019-08-29 11:06
閱讀 1011·2019-08-26 18:26
閱讀 1062·2019-08-26 13:53
閱讀 2538·2019-08-26 12:21