0 - 重要
有了上一篇文章中對框架的理解蟀拷,現(xiàn)在來講一下Django具體的打開方式,最好的方法自然是依附于一個(gè)項(xiàng)目允粤。
本文主要是基于Django 博客開發(fā)入門教程做的二次開發(fā)崭倘,因此,你可能需要先完整的做一遍這個(gè)教程维哈,再繼續(xù)讀下去绳姨。
我是先照著教程做了一個(gè)一模一樣的博客,因?yàn)檎娴氖且荒R粯拥睦樱跃筒环懦鰜砹似W龅倪^程中也閱讀了Django的官方文檔,為了確保我對Django的理解都是正確的购撼,以及有些地方對于這個(gè)博客我也有點(diǎn)自己的想法跪削,于是我又做了個(gè)類似的網(wǎng)站。我所作的改動(dòng)我會(huì)一一列舉出來迂求。
我做了個(gè)什么碾盐?
我的想法是做一個(gè)內(nèi)容展示的平臺(tái),主要是用來展示各種爬蟲抓取到的內(nèi)容揩局,具體的文字采用MD格式毫玖。雖然我很想直接做個(gè)通用平臺(tái),但是時(shí)間有限凌盯,而且也沒找到什么好看的頁面模板付枫,就先擱下了。這里我還是找了一個(gè)類博客的模板驰怎,用的內(nèi)容資源是之前爬取百度貼吧時(shí)的帖子內(nèi)容阐滩。
當(dāng)前的測試內(nèi)容是從百度貼吧里抓取到的10個(gè)帖子,分別來源于來個(gè)dota2
和復(fù)仇者聯(lián)盟
吧县忌。在項(xiàng)目里掂榔,每個(gè)貼吧對應(yīng)一個(gè)Category
继效,每個(gè)帖子對應(yīng)一個(gè)Sticker
。
1 - 改動(dòng)的地方
關(guān)于設(shè)計(jì)模板和模板標(biāo)簽語言
我們已經(jīng)知道在Django中装获,一個(gè)網(wǎng)頁會(huì)由兩部分組成:靜態(tài)文件(js, css, img...)和HTML文檔瑞信。前者讓網(wǎng)站變得美觀,而后者則定義了網(wǎng)站的結(jié)構(gòu)和功能饱溢。Django則提供了一些方法用來動(dòng)態(tài)生成HTML文檔喧伞,這些方法被稱為標(biāo)簽,標(biāo)簽有很多種绩郎,我從兩個(gè)大括號(hào):{{ xxxxx }}
說起潘鲫。
這類標(biāo)簽官方?jīng)]有命名,但說明了它返回的是被符號(hào)包含的語句的屬性值肋杖,這個(gè)值可以直接來源于某個(gè)變量溉仑,也可以來源于某個(gè)函數(shù)。大多數(shù)情況状植,我們傳入一個(gè)頁面的參數(shù)是一個(gè)模型實(shí)例(定義在models.py里)或由若干實(shí)例組成的一個(gè)QuerySet浊竟,后者則通常是由自定義標(biāo)簽返回的。又一般而言津畸,我們會(huì)對QuerySet里的對象進(jìn)行遍歷振定,所有說到底{{ xxxxx }}
操作的對象是一個(gè)模型實(shí)例,因此它可以調(diào)用這個(gè)模型里所有的成員方法(模型本質(zhì)上是一個(gè)類)肉拓。
這段話怎么理解后频?舉個(gè)例子,參考base.html
和index.html
:
base.html
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
.....meta contents
</head>
<body>
<header>
{% include "common/navigation.html" %}
</header>
<div class="widewrapper main">
<div class="container">
<div class="row">
<div class="col-md-8 blog-main">
{% block main %}
{% endblock main %}
</div>
<aside class="col-md-4 blog-aside">
<div class="aside-widget">
{% include "common/feature.html" %}
</div>
<div class="aside-widget">
{% include "common/tags.html" %}
</div>
</aside>
</div>
</div>
</div>
<footer>
{% include "common/footer.html" %}
</footer>
<script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
<script src="{% static 'js/modernizr.js' %}"></script>
</body>
</html>
index.html
{% extends 'base.html' %}
{% load staticfiles %}
{% load customTags %}
{% block main %}
<div class="row">
{% get_all_categories as categories_list %}
{% for category in categories_list %}
<div class="col-md-6 col-sm-6">
<article class=" blog-teaser">
<header>
<p>
<a href="{{ category.get_absolute_url }}">
<img src="{% static 'images/' %}{{ category.name }}/{{ category.name }}.jpg" alt=""></p>
<h3><a href="{{ category.get_absolute_url }}">{{ category.name }}</a></h3>
</header>
<hr>
</article>
</div>
{% empty %}
暫無內(nèi)容暖途!
{% endfor %}
</div>
{% endblock main %}
當(dāng)訪問的URL為/
時(shí)卑惜,會(huì)返回index.html
頁面,這個(gè)頁面首先繼承了base.html
(用{% extends 'base.html' %}
標(biāo)簽)驻售。這意味這index.html
的內(nèi)容會(huì)和base.html
里的內(nèi)容一起返回給客戶端露久,base.html
里會(huì)用{% block %}
和{% endblock %}
預(yù)留位置,之后在index.html
中補(bǔ)足欺栗,block
也可以命名毫痕,這個(gè)不難理解。
我這里是將base.html
作為最基礎(chǔ)的模板迟几,因此我想將它做的盡可能地簡潔同時(shí)易于閱讀消请,于是我將其進(jìn)一步的分割開來,剝離出了feature.html
, footer.html
, navigation.html
和tags.html
瘤旨,它們分別對應(yīng)了頁面上的一部分小頁面梯啤,通過{% include %}
標(biāo)簽竖伯,index.html
可以將它們都包裹進(jìn)來存哲。
回到index.html
因宇,我們用{% load %}
標(biāo)簽載入了兩個(gè)模塊,staticfiles
定義了靜態(tài)資源的路徑祟偷,customTags
則是我自定義的標(biāo)簽(如果你不知道自定義標(biāo)簽是什么察滑,回頭看看文章開始部分提到的博客)。在我的自定義標(biāo)簽里我定義了一個(gè)名為get_all_categories
的方法(注意這個(gè)方法是可以帶參數(shù)的修肠,參數(shù)通過get_all_categories param1 param2 ...
的方式傳入)用來獲取所有的分類贺辰,它返回的是一個(gè)QuerySet類型的變量,這個(gè)后面會(huì)說嵌施。通過{% for %}
, {% empty %}
和{% endfor %}
饲化,可以對這個(gè)set進(jìn)行遍歷,生成一系列結(jié)構(gòu)一致的HTML結(jié)構(gòu)吗伤。for標(biāo)簽是可以多層嵌套的吃靠。
另一種很有用的物件叫**過濾器 **,用管道符|
表示足淆,它相當(dāng)于一種快捷的自定義標(biāo)簽巢块,用于快速的處理對象內(nèi)容,過濾器和標(biāo)簽其實(shí)是差不多的東西巧号,也可以互相轉(zhuǎn)化族奢。值得一提的是,過濾器具有管道特性丹鸿,因此它可以像這樣使用:{{ content|filter1|filter2|... }}
越走。
最后還有一些沒提到但是很常用的標(biāo)簽列舉在這,僅供瀏覽:
-
{% if condition %}
,{% elif condition2
卜高,{% else %}
和{% endif %}
-
{% ifequal val1 val2 %}
和{% ifnotequal val1 val2 %}
- 配合else:
{% ifequal val1 val2 %}
,{% else %}
和{% endifequal %}
弥姻,ifnotequal同理。
- 配合else:
-
{# #}
注釋
都很容易理解掺涛。Django稱這些標(biāo)簽為The Django template language庭敦,同時(shí)列出了所有可以用的標(biāo)簽Built-in template tags and filters。通過使用模板可以使代碼的結(jié)構(gòu)變得清晰薪缆,通過使用標(biāo)簽秧廉,可以“動(dòng)態(tài)”生成網(wǎng)頁的內(nèi)容。
關(guān)于URL的參數(shù)傳遞
上一節(jié)中拣帽,single.html
中使用的category
是從自定義標(biāo)簽中的一個(gè)方法返回的疼电,我們也可以在生成頁面的時(shí)候直接給頁面?zhèn)鬟f一個(gè)內(nèi)容。
首先梳理一下一個(gè)請求的處理流程减拭,以訪問/sticker/a7f85c00424ed045316b7f8eed7e0a04/
為例:
瀏覽器發(fā)起請求蔽豺,URL為
http://127.0.0.1:8000/sticker/a7f85c00424ed045316b7f8eed7e0a04/
。-
在
urls.py
中會(huì)匹配到url(r'^sticker/(?P<md5>[0-9a-z]+)/$', views.singleDetailView.as_view(), name='single')
這一條正則表達(dá)式拧粪。這里我們抓取的是sitcker/????/
中????
的值修陡,因?yàn)槲抑肋@是一個(gè)md5值沧侥,所以過濾的規(guī)則是所有小寫字母和數(shù)字。通過?P
可以對抓取出來的內(nèi)容命名魄鸦,因此這里會(huì)得到一個(gè)類似{'md5': a7f85c00424ed045316b7f8eed7e0a04}
的字典對象宴杀,有多個(gè)?P
的話字典中自然也有多個(gè)值。然后這個(gè)字典會(huì)被作為參數(shù)傳入singleDetailView
的一個(gè)實(shí)例對象拾因,在這個(gè)對象中旺罢,你可以使用self.kwargs['md5']
訪問到這個(gè)值。在這個(gè)對象中绢记,默認(rèn)定義了三個(gè)變量:-
model = Sticker
:這個(gè)視圖(本質(zhì)上就是個(gè)類)對應(yīng)的模型扁达,此處是Sticker
(在models.py中定義)。 -
template_name = 'single.html'
和context_object_name = 'sticker'
表示這個(gè)實(shí)例要作為名為sticker
的參數(shù)傳入single.html
中蠢熄。
-
如果你沒有什么特殊需求罩驻,那么
singleDetailView
中只要制定這三個(gè)變量即可。但是我們這里想要返回的其實(shí)是md5
值為a7f85c00424ed045316b7f8eed7e0a04
的sticker
對象护赊,因此我們要重寫get_object
方法惠遏,根據(jù)md5值找到其對應(yīng)的sticker
對象,此處不表骏啰。這個(gè)
sticker
對象會(huì)作為參數(shù)傳入single.html
节吮,之后你就可以在single.html
中通過類似{{ sticker.title }}
或{{ sticker.author }}
的標(biāo)簽來生成特定的頁面了。最后自然就是將這個(gè)定制過的
single.html
返回給客戶端了判耕。
Django 如何處理一個(gè)請求 - 官方版
Django 如何處理一個(gè)請求: https://docs.djangoproject.com/zh-hans/2.0/topics/http/urls/#how-django-processes-a-request 寫道:
當(dāng)一個(gè)用戶請求Django 站點(diǎn)的一個(gè)頁面透绩,下面是Django 系統(tǒng)決定執(zhí)行哪個(gè)Python 代碼使用的算法:
1. Django determines the root URLconf module to use. Ordinarily, this is the value of the ROOT_URLCONF setting, but if the incoming HttpRequest object has a urlconf attribute (set by middleware), its value will be used in place of the ROOT_URLCONF setting.
2. Django loads that Python module and looks for the variable urlpatterns. This should be a Python list of django.urls.path() and/or django.urls.re_path() instances.
3. Django 依次匹配每個(gè)URL 模式,在與請求的URL 匹配的第一個(gè)模式停下來壁熄。
4. Once one of the URL patterns matches, Django imports and calls the given view, which is a simple Python function (or a class-based view). The view gets passed the following arguments:
- 一個(gè) HttpRequest 實(shí)例帚豪。
- If the matched URL pattern returned no named groups, then the matches from the regular expression are provided as positional arguments.
- The keyword arguments are made up of any named parts matched by the path expression, overridden by any arguments specified in the optional kwargs argument to django.urls.path() or django.urls.re_path().
5. If no URL pattern matches, or if an exception is raised during any point in this process, Django invokes an appropriate error-handling view. See Error handling below.
這里我覺得第四點(diǎn)比較重要,它說在傳遞URL中的參數(shù)給視圖時(shí)草丧,有可能傳入三種不同的參數(shù):
- 一個(gè)HTTPRequest實(shí)例狸臣,如果你足夠聰明,很容易就可以猜到這個(gè)實(shí)例的名字叫
request
因此昌执,在這個(gè)視圖對應(yīng)的模板文件里烛亦,可以使用類似{{ request.xxx }}
來訪問HTTPRequest對象的所有方法,這有時(shí)候很有用懂拾。 - 正則中使用
()
來代表需要抓取的內(nèi)容煤禽,如上文所述,我們使用?P
來命名這個(gè)抓取到的內(nèi)容岖赋,但是如果不命名呢檬果?它會(huì)按照順序傳回抓取到的內(nèi)容,但是官方表示不推薦這種用法,所以我也不用选脊。這是第二種參數(shù)衷畦。 - 第三種參數(shù),就是我們上文中所述的參數(shù)知牌,應(yīng)該也是最常用的方法。
通過傳統(tǒng)的”?”傳遞參數(shù)斤程?
那么能不能通過傳統(tǒng)的?
方式傳入?yún)?shù)呢角寸?答案是肯定的,還記得傳入的那個(gè)HTTPRequest實(shí)例嗎忿墅?它有一個(gè)方法為GET
扁藕,解釋為A dictionary-like object containing all given HTTP GET parameters.
,如果URL是..../s.html?p1=v1
疚脐,可以通過request.GET.get('p1')
訪問亿柑。
至于這個(gè)參數(shù)能不能直接用正則匹配出來,我覺得是可以的棍弄,但是我沒試過望薄。
為什么用md5?
類視圖其實(shí)默認(rèn)是傳入pk
參數(shù)的呼畸,也就是主鍵痕支,這是你在初始化數(shù)據(jù)庫時(shí)Django自動(dòng)生成的。一開始蛮原,我只是單純的想試試能不能傳入別的參數(shù)卧须,后來發(fā)現(xiàn)其實(shí)用md5
也好,可以起到一定的反爬蟲的功效儒陨?
sticker還是sticker?
看singleDetailView
的內(nèi)容:
class singleDetailView(DetailView):
model = Sticker
template_name = 'single.html'
context_object_name = 'sticker'
def get_object(self, queryset=None):
sticker = get_object_or_404(Sticker, md5=self.kwargs['md5'])
sticker.increase_views()
sticker.content = markdown.markdown(sticker.content,
extensions=[
'markdown.extensions.extra',
'markdown.extensions.codehilite',
'markdown.extensions.toc',
])
return sticker
這里有兩個(gè)sticker
花嘶,代碼當(dāng)然沒問題,但是改寫一些會(huì)更好理解:
class singleDetailView(DetailView):
model = Sticker
template_name = 'single.html'
context_object_name = 'sticker'
def get_object(self, queryset=None):
obj = get_object_or_404(Sticker, md5=self.kwargs['md5'])
obj.increase_views()
obj.content = markdown.markdown(obj.content,
extensions=[
'markdown.extensions.extra',
'markdown.extensions.codehilite',
'markdown.extensions.toc',
])
return obj
如上文所述蹦漠,重寫的get_object
方法會(huì)返回一個(gè)Sticker
對象或模型椭员,它是根據(jù)md5
的值篩選出來的。這個(gè)對象obj
會(huì)被賦予另一個(gè)名為sticker
的變量里笛园,然后傳入single.html
中拆撼,這里只是恰好使用了相同的名字。
關(guān)于帖子主題內(nèi)容的格式
網(wǎng)站的測試內(nèi)容喘沿,我是從網(wǎng)站直接抓過來的闸度,它被轉(zhuǎn)化為Markdown格式,之后再通過Markdown庫渲染成HTML格式蚜印。因此這里其實(shí)有一個(gè)HTML -> MD -> HTML的過程莺禁。私以為這不是多余的,這樣做可以過濾掉很多雜亂的HTML標(biāo)簽窄赋。如果網(wǎng)站的內(nèi)容來源是很多不同的網(wǎng)站哟冬,優(yōu)勢會(huì)更加明顯楼熄。
長URL換行問題
有時(shí)候帖子內(nèi)容中會(huì)包含一個(gè)很長的URL,這個(gè)URL不會(huì)自動(dòng)換行浩峡,因此可能會(huì)超出當(dāng)前的CSS block可岂,影響美觀。我在網(wǎng)上查到了兩種解決方法:(django問題)處理換行和空格翰灾,第二種我這沒生效缕粹。
關(guān)于ORM和數(shù)據(jù)操作
雖然Django后端使用的是sqlite3(也可以換成其他的),但是我們并不需要編寫SQL語句來操作它(但是這也是可以的)纸淮。
Django對數(shù)據(jù)操作進(jìn)行了封裝平斩,這使得我們可以通過使用Python語言直接操作數(shù)據(jù),這個(gè)過程就叫做ORM咽块,即Object-relational mapping绘面。
存入數(shù)據(jù)
這里我們已經(jīng)知道,Django中的數(shù)據(jù)模型其實(shí)就是繼承了db.models
的類侈沪,在默認(rèn)文件models.py
中定義揭璃。 這個(gè)類中定義的屬性即對應(yīng)了表中的一個(gè)字段,同時(shí)db.models
中也定義了所有可用的字段類型亭罪。注意一對一塘辅、一對多、多對多關(guān)系的表示方法皆撩。
需要注意的是扣墩,只要你對models.py
中的內(nèi)容 進(jìn)行了修改,就需要執(zhí)行:
python manage.py makemigrations
python manage.py migrate
完成數(shù)據(jù)庫的遷移扛吞,可以理解為刷新呻惕。
完成了數(shù)據(jù)庫遷移后,你就可以使用代碼直接向數(shù)據(jù)庫中寫入數(shù)據(jù)了滥比,下面會(huì)提到亚脆。
讀取數(shù)據(jù)
從數(shù)據(jù)庫中讀取數(shù)據(jù),最重要的內(nèi)容就是QuerySet
對象盲泛。值得一提的是濒持,QuerySet
對象是Lazy的(想一想生成器),這個(gè)怎么理解呢寺滚?QuerySet
對象的一個(gè)特性就是它可以進(jìn)行鏈?zhǔn)讲僮鞲逃紤]一下代碼:
r = CustomM.objects.all().filer(pk__gt=12).filter(...). ..........filert(...)
理論上你可以無限進(jìn)行鏈?zhǔn)讲僮鳎@里的trick就是雖然這行代碼被執(zhí)行了村视,但實(shí)際上這里面沒有設(shè)計(jì)到數(shù)據(jù)庫的行為考廉。那么什么時(shí)候會(huì)產(chǎn)生數(shù)據(jù)庫行為呢庸蔼?文檔上說的是`當(dāng)這個(gè)對象被evaluated的時(shí)候寄疏。哈哈,下個(gè)問題自然是對象什么時(shí)候會(huì)被evaluated呢疲扎?答案是When QuerySets are evaluated。這個(gè)文檔里列舉所有會(huì)造成數(shù)據(jù)庫行為的操作,這對寫代碼會(huì)有幫助。
在同一篇文檔里:QuerySet API reference, 里面列舉了所有QuerySet
對象的操作另伍,在我的代碼里,我其實(shí)只用到了很有限的幾個(gè):all()
, order_by
, filter()
和values()
绞旅。關(guān)于這些API摆尝,我想我會(huì)另開文檔說一說,畢竟實(shí)在是太多了玻靡。
理論上,通過這些API可以完成所有的數(shù)據(jù)庫操作中贝,不管是簡單的還是復(fù)雜的SQL語句囤捻。事實(shí)上呢?
關(guān)于批量導(dǎo)入數(shù)據(jù)庫
通過合理的開發(fā)邻寿,我們當(dāng)然可以在Admin頁面中手動(dòng)添加數(shù)據(jù)蝎土。但是第一次啟動(dòng)網(wǎng)站時(shí),我們可能會(huì)需要導(dǎo)入一些初始數(shù)據(jù)绣否。Django提供了兩種方法用來向數(shù)據(jù)庫寫入數(shù)據(jù)誊涯,假如models.py
中定義了一個(gè)名為Sticker
的模型:
-
Sticker(name=yourname).save()
-
Sticker
的參數(shù)列表需要對應(yīng)數(shù)據(jù)結(jié)構(gòu)中的字段名,save()
將其生成的對象寫入數(shù)據(jù)庫中蒜撮。
-
-
Sticker.objects.create(title = title, author = author, content = content, category = c, md5 = md5)
- 同樣
create
的參數(shù)列表需要對應(yīng)數(shù)據(jù)結(jié)構(gòu)中的字段名暴构。
- 同樣
在Django項(xiàng)目的根目錄下,可以執(zhí)行python manage.py shell
進(jìn)入一個(gè)交互界面段磨,然后就可以使用上述方法了取逾。但是,我們更想做的應(yīng)該是在一個(gè)Python文件中執(zhí)行這些代碼苹支。
你只需要在項(xiàng)目根目錄下新建一個(gè)python文件砾隅,然后執(zhí)行它就行了。這里放上我的代碼:
# 這個(gè)一定要债蜜,不然會(huì)報(bào)錯(cuò)晴埂,但是錯(cuò)誤很明顯,容易定位寻定。
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gallery.settings")
# django版本大于1.7時(shí)需要這兩句
import django
django.setup()
import hashlib
# 導(dǎo)入你需要寫入的兩個(gè)模型類
from sticker.models import Category, Sticker
# 第一種方法寫入數(shù)據(jù)庫
dirname = '分類1'
c = Category(name=dirname)
c.save()
file_dir = r"D:\OneDrive\Download\"
# 這里我是遍歷了file_dir中的所有文件儒洛,并依次解析它們
for file in os.listdir(file_dir):
with open(file_dir+'\\'+file, 'r', encoding='utf-8') as file:
title = file.readline().split(':')[1].strip() # 獲取第一行title值
author = file.readline().split(':')[1].strip() # 獲取第二行author值
content = file.read().strip() # 讀取剩余內(nèi)容,作為content狼速,即post的內(nèi)容
# 根據(jù)content生成md5
m = hashlib.md5()
m.update(content.encode('utf-8'))
md5 = m.hexdigest()
# 第二種方法寫入數(shù)據(jù)庫
Sticker.objects.create(title = title,
author = author,
content = content,
category = c,
md5 = md5
)
關(guān)于圖片外鏈
雖然抓取到的內(nèi)容中的圖片的鏈接都是絕對路徑晶丘,但是如果直接在網(wǎng)站上使用,會(huì)被認(rèn)為是盜鏈導(dǎo)致圖片無法顯示。(怎么識(shí)別盜鏈的浅浮?)
關(guān)于這一點(diǎn)沫浆,我想到了三種解決方法:
-
將圖片全部下載到本地,這是我目前使用的方法滚秩,也是我最不贊成使用的方法专执。這不僅使得本地文件過多,而且也不容易管理郁油。
不過我仍然解釋下我這里是怎么做的:
首先本股,用爬蟲去爬取每個(gè)帖子,過濾出所有的圖片桐腌,并將其下載到本地拄显,命名為
tid_cnt.jpg
,tid
是這個(gè)帖子的唯一id案站,cnt
則是一個(gè)簡單的遞增值躬审。之后將所有的圖片都處理成md的語義:[圖片上傳失敗...(image-d1bc88-1532185791647)]
。這樣其實(shí)已經(jīng)可以了蟆盐,如果要分細(xì)一點(diǎn)承边,可以在images
后再加入不容的目錄。之后石挂,再將帖子刷入數(shù)據(jù)庫后博助,將下載下來的圖片都放到
static/images/
下面,也就是網(wǎng)站的靜態(tài)資源目錄下痹愚,這樣就可以正常訪問圖片了富岳。 -
第二種方法就是使用云主機(jī),有一些現(xiàn)成的在線圖片外鏈生成站拯腮,最有名的就是七牛云了城瞎。
這里我在推薦一個(gè)輕量級的站,名為SM.MS, 但是會(huì)有上傳數(shù)量限制疾瓮,不符合我的需求脖镀。這里提供一個(gè)Python版的代碼,最后的
data
是一個(gè)字典狼电,里面包含了生成的外鏈蜒灰。import requests import json image_path = 'mvey0559.jpg' # 要上傳的圖片路徑 url = 'https://sm.ms/api/upload' files = {'smfile' : open(image_path, 'rb')} content = None try: response = requests.post(url, files=files) if response.status_code == requests.codes.ok: content = response.text except Exception as e: print (e) data = json.loads(content) print (data)
最后一種方法自然就是自己部署一個(gè)圖床服務(wù)器了。目前我搜集到的信息是使用FastDFS + Python的方法:FastDFSClient_Python肩碟。但是能不能再封裝成Web形式暫時(shí)還不知道强窖,另外能不能做成只能給自己的網(wǎng)站使用的接口呢?有空我再研究研究削祈。