通常當(dāng)我們談到開發(fā)網(wǎng)站時(shí),我們都是指生成一些HTML
當(dāng)然也有很多HTML之外的東西,我們使用web來發(fā)布所有的內(nèi)容,不僅僅是HTML
到目前為止我們都是在關(guān)注通常的HTML生成,但是本章將繞道來看看使用Django生成其它類型的內(nèi)容
你可以使用Django方便的內(nèi)建工具來生成一些常見的非HTML內(nèi)容:
RSS/Atom聚合
Sitemaps,可以被Google,Yahoo和微軟的搜索引擎搜索
JSON和XML序列化的模型(通常為AJAX方法使用)
我們將談到上面的每一個(gè)工具,但是首先來看看一些基礎(chǔ)
基礎(chǔ)
還記得第3章的內(nèi)容嗎?
視圖方法或者簡短來說視圖是簡單的Python方法,它得到Web請求并返回Web應(yīng)答,這個(gè)應(yīng)答可以是Web頁面的HTML內(nèi)容,
或者是一個(gè)重定向,或者是404錯(cuò)誤,或者是一個(gè)XML文檔,或者是一個(gè)image,...,或者是其它的任何東西
更正式的,Django視圖方法必須接受一個(gè)HttpRequest實(shí)例作為它的第一個(gè)參數(shù)并且返回一個(gè)HttpResponse實(shí)例
從視圖返回非HTML內(nèi)容的關(guān)鍵在于HttpResponse類,特別是mimetype構(gòu)造函數(shù)的參數(shù),通過改變mimetype我們可以指示
瀏覽器我們返回的不同類型的對象
下面是一個(gè)簡單的例子,我們來看看一個(gè)返回PNG圖像的視圖,為了讓事情保持簡單,我們只是從硬盤讀一個(gè)文件:
- from django.http import HttpResponse
- def my_image(request):
- image_data = open("/path/to/my/image.png", "rb").read()
- return HttpResponse(image_data, mimetype="image/png")
僅此而已!如果你改變open()調(diào)用的圖像路徑為一個(gè)真正圖像的路徑,你可以使用這個(gè)非常簡單的視圖來處理圖像,瀏覽
器將正確的顯示它
另外一個(gè)需要記住的重要事情是HttpResponse對象實(shí)現(xiàn)了Python的標(biāo)準(zhǔn)文件API,這意味著你可以傳遞一個(gè)HttpResponse
實(shí)例給Python(或者第三方庫)需要文件的任何地方
例如我們看看用Django生成CSV
生成CSV
CSV是通常被電子制表軟件使用的簡單數(shù)據(jù)形式,它基本上是表的一系列行,行的每個(gè)單元用逗號(hào)分隔(CSV表示"逗號(hào)分隔
的值"),例如,下面是FAA收集的最近10年的"不規(guī)矩"的航空旅客的列表:
- Year,Unruly Airline Passengers
- 1995,146
- 1996,184
- 1997,235
- 1998,200
- 1999,226
- 2000,251
- 2001,299
- 2002,273
- 2003,281
- 2004,304
- 2005,203
注意參看http://www.faa.gov/data_statistics/passengers_cargo/unruly_passengers/得到此數(shù)據(jù)
不幸的是,CSV不是正式定義的格式,軟件的不同部分生成和使用不同的CSV,這讓它有點(diǎn)難以使用
幸運(yùn)的是,Python有一個(gè)標(biāo)準(zhǔn)CSV庫csv,它是非常防彈的
和Django使用這個(gè)庫的關(guān)鍵是csv模塊的CSV創(chuàng)建能力表現(xiàn)為類似文件對象,Django的HttpResponse對象也類似文件對象:
- import csv
- from django.http import HttpResponse
- # Number of unruly passengers each year 1995 - 2005
- UNRULY_PASSENGERS = [146,184,235,200,226,251,299,273,281,304,203]
- def unruly_passengers_csv(request):
- # Create the HttpResponse object with the appropriate CSV header.
- response = HttpResponse(mimetype='text/csv')
- response['Content-Disposition'] = 'attachment; filename=unruly.csv'
- # Create the CSV writer using the HttpResponse as the "file"
- writer = csv.writer(response)
- writer.writerow(['Year', 'Unruly Airline Passengers'])
- for (year, num) in zip(range(1995, 2006), UNRULY_PASSENGERS):
- writer.writerow([year, num])
- return response
代碼和注釋看起來非常清楚,但是有一些事情需要注意:
1,應(yīng)答的mime-type為為text/csv,這告訴瀏覽器文檔是一個(gè)CSV文件,而不是HTML文件
2,應(yīng)答有一個(gè)另外的Content-Disposition頭部,它包含CSV文件的名字,這個(gè)頭部("attachment")將告訴瀏覽器提示
一個(gè)位置來保存文件(而不是顯示它),這個(gè)文件名隨意,你想叫它什么都可以,它將被瀏覽器的"Save as..."對話框使用
3,CSV生成API很簡單,只是傳遞response作為第一個(gè)參數(shù)給csv.writer,csv.writer方法期望一個(gè)類似文件的對象,
然后HttpResponse對象來付帳
4,對你的CSV文件的每一行調(diào)用writer.writerow,傳遞一個(gè)iterable對象給它,例如列表或者元組
5,CSV模塊幫你關(guān)注引號(hào),所以你不需要擔(dān)心escape含有引號(hào)或逗號(hào)的字符串,只需傳遞信息給writerow(),它將給你
做正確的事情
你通常將重復(fù)這個(gè)模式,創(chuàng)建一個(gè)HttpResponse應(yīng)答對象(用一個(gè)特殊的mime-type),把它傳遞給一個(gè)期望文件的東西,
然后返回應(yīng)答,任何你生成非HTML內(nèi)容的時(shí)候都可以這樣做
讓我們看看一些更多的例子
生成PDF
PDF(Portable Document Format)是Adobe開發(fā)的格式,它用來展示可打印的文檔,并具有象素完美的格式,內(nèi)嵌的字體和
2D向量圖形,你可以把PDF文檔當(dāng)作可打印文檔的數(shù)字等價(jià)物,確實(shí),PDF通常用在當(dāng)你需要把一份文檔給另一個(gè)人打印時(shí)
有了絕佳的ReportLab開源庫(http://www.reportlab.org/rl_toolkit.html)你可以使用Python和Django輕松
生成PDF,動(dòng)態(tài)生成PDF文件的好處是你可以創(chuàng)建自定義的PDF來滿足不同的目的,如為不同的用戶或不同的內(nèi)容等
例如,我們在KUSports.com使用Django和ReportLab來為參加March Madness(大學(xué)籃球賽)的人們生成自定義的可打印的
NCAA錦標(biāo)賽brackets
安裝ReportLab
但是,在你生成任何PDF之前你需要安裝ReportLab,這通常很簡單
只需從http://www.reportlab.org/downloads.html下載和安裝庫
用戶手冊(不巧也是PDF文件)在http://www.reportlab.org/rsrc/userguide.pdf并有額外的安裝幫助
注意,如果你使用時(shí)髦的Linux發(fā)布,你可能想在手動(dòng)安裝ReportLab前檢查你的包管理工具,大部分包資源庫已經(jīng)
包含了ReportLab,例如,如果你使用(絕佳的)Ubuntu發(fā)布,一個(gè)簡單的aptitude install python-reportlab將很好的
安裝它
通過在Python交互解釋器里import它來測試你的安裝:
- >>> import reportlab
如果上面的命令不觸發(fā)任何錯(cuò)誤,表明安裝的組件已經(jīng)工作
寫視圖
再說一遍,使用Django動(dòng)態(tài)生成PDF的關(guān)鍵是ReportLab API基于類似文件的對象,而且Django的HttpResponse對象也是
類似文件的對象,這里是一個(gè)"Hello World"例子:
- from reportlab.pdfgen import canvas
- from django.http import HttpResponse
- def hello_pdf(request):
- # Create the HttpResponse object with the appropriate PDF headers.
- response = HttpResponse(mimetype='application/pdf')
- response['Content-Disposition'] = 'attachment; filename=hello.pdf'
- # Create the PDF object, using the response object as its "file."
- p = canvas.Canvas(response)
- # Draw things on the PDF. Here's where the PDF generation happens.
- # See the ReportLab documentation for the full list of functionality.
- p.drawString(100, 100, "Hello world.")
- # Close the PDF object cleanly, and we're done.
- p.showPage()
- p.save()
- return response
和上面一樣,有一些地方需要按順序注意一下:
1,這里我們使用application/pdf mime-type,這告訴瀏覽器文檔是一個(gè)PDF文件,而不是一個(gè)HTML文件,如果你不寫
這個(gè),瀏覽器將可能把輸出解釋為HTML,這將導(dǎo)致在瀏覽器觸發(fā)錯(cuò)誤
2,ReportLab API很簡單,只需把response作為第一個(gè)參數(shù)傳遞給canva.Canvas,Canvas類期望一個(gè)類似文件的對象,
然后HttpResponse對象來付帳
3,所有后面的PDF生成方法在PDF對象(這里是p)上調(diào)用,而不是在response上
4,最后,在PDF文件上調(diào)用showPage()和save()很重要(否則你將得到一個(gè)糟糕的PDF文件)
復(fù)雜的PDF
如果你使用ReportLab創(chuàng)建一個(gè)復(fù)雜的PDF文檔,考慮為你的PDF文件使用cStringIO庫作為一個(gè)臨時(shí)存儲(chǔ)位置,cStringIO
庫提供一個(gè)非常有效的類似文件的對象接口(比天真的HttpResponse作為文件的實(shí)現(xiàn)更好)
這里是使用cStringIO來重寫上面的"Hello World"例子:
- from cStringIO import StringIO
- from reportlab.pdfgen import canvas
- from django.http import HttpResponse
- def hello_pdf(request):
- # Create the HttpResponse object with the appropriate PDF headers.
- response = HttpResponse(mimetype='application/pdf')
- response['Content-Disposition'] = 'attachment; filename=hello.pdf'
- buffer = StringIO()
- # Create the PDF object, using the StringIO object as its "file."
- p = canvas.Canvas(buffer)
- # Draw things on the PDF. Here's where the PDF generation happens.
- # See the ReportLab documentation for the full list of functionality.
- p.drawString(100, 100, "Hello world.")
- # Close the PDF object cleanly.
- p.showPage()
- p.save()
- # Get the value of the StringIO buffer and write it to the response.
- response.write(buffer.getvalue())
- return response
其它可能性
用Python你可以生成整個(gè)世界的其它類型的內(nèi)容,這里是一些更多的主意,其中一些是你可以用來實(shí)現(xiàn)它們的庫:
生成ZIP文件:Python的zipfile模塊的標(biāo)準(zhǔn)庫,它可以讀寫壓縮的ZIP文件,你可以使用它來提供任意文件的存檔,
或者有需求時(shí)把大文檔壓縮,你同樣可以使用標(biāo)準(zhǔn)庫的tarfile模塊來生成TAR文件
動(dòng)態(tài)圖像生成:Python圖像庫(http://www.pythonware.com/products/pil/)是一個(gè)非常奇妙的用來生成圖像
(PNG,JPEG,GIF等等)的工具庫,你可以用它來自動(dòng)縮小圖像,把多幅圖像組合成單獨(dú)畫面,甚至做基于web的圖像處理
分圖和制圖:有許多不可思議的強(qiáng)大的Python分圖和制圖庫,你可以用它們生成任意的maps,charts,plots和graphs
我們不能列出所有的,所以這里是一些不錯(cuò)的:
matplotlib(http://matplotlib.sourceforge.net/),它可以用來生成通常用MatLab或者M(jìn)athematica來生成
的高質(zhì)量的plots
pygraphviz(https://networkx.lanl.gov/wiki/pygraphviz)
這是一個(gè)Graphviz圖形布局工具庫(http://graphviz.org/)的接口,用來生成圖形或網(wǎng)絡(luò)的結(jié)構(gòu)化diagrams
通常來說,任何可以寫文件的Python庫都可以在Django中使用,可能性真的是無限的
既然我們看到了生成非HTML內(nèi)容的基礎(chǔ),讓我們進(jìn)一步抽象,Django帶有一些非常俏皮的內(nèi)建工具用來生成一些通常類型
的非HTML內(nèi)容
聚合框架
Django帶有一個(gè)高級的聚合生成框架,它讓創(chuàng)建RSS和Atom feeds非常容易
什么是RSS?什么是Atom?
RSS和Atom都是基于XML的格式,你可以用來提供自動(dòng)更新你的站點(diǎn)內(nèi)容的"feeds"
閱讀更多關(guān)于RSS的內(nèi)容http://www.whatisrss.com
以及更多關(guān)于Atome的內(nèi)容http://www.atomenabled.org
創(chuàng)建任何聚合只需寫一個(gè)很短的Python類,你可以想創(chuàng)建多少feeds就創(chuàng)建多少
Django也帶一個(gè)低級feed生成API,如果你想在Web context之外生成feeds或者用一些更低級的方式的話可以使用它
高級框架概覽
高級feed生成框架是一個(gè)默認(rèn)綁定到/feeds/的視圖,Django使用URL的其它部分(在/feeds/之后的任何東西)來決定輸出
哪個(gè)feed
為了創(chuàng)建一個(gè)feed,只需寫一個(gè)Feed類并在你的URL配置里指出(參考第3章和第8章得到更多關(guān)于URL配置)
初始化
為了在你的Django站點(diǎn)里激活聚合,你需要把下面的內(nèi)容添加到你的URL配置:
- (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', {'feed_dict': feeds}),
這會(huì)告訴Django使用RSS框架來處理所有的以"feeds/"開頭的URL(你可以改變"feeds/"前綴來滿足你自己的需求)
這個(gè)URL配置有另外一個(gè)參數(shù){'feed_dict': feeds},使用這個(gè)額外參數(shù)來把改URL下發(fā)布的feeds傳遞給聚合框架
特別的,feed_dict應(yīng)該是一個(gè)映射feed的slug(簡短URL標(biāo)簽)到它的Feed類的字典
你可以在URL配置本身里定義feed_dict,這里是一個(gè)完整的例子:
- from django.conf.urls.defaults import *
- from myproject.feeds import LatestEntries, LatestEntriesByCategory
- feeds = {
- 'latest': LatestEntries,
- 'categories': LatestEntriesByCategory,
- }
- urlpatterns = patterns('',
- # ...
- (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
- {'feed_dict': feeds}),
- # ...
- )
上面的例子注冊了兩個(gè)feeds:
通過LatestEntries展示的feed對應(yīng)feeds/latest/
通過LatestEntriesByCategory展示的feed對應(yīng)feeds/categories/
一旦建立好之后,你只需定義Feed類本身
Feed類
一個(gè)Feed類是展示聚合feed的簡單的Python類,一個(gè)Feed可以很簡單(例如一個(gè)"站點(diǎn)新聞"feed或者顯示博客最近條目的
基本feed)也可以更復(fù)雜(例如顯示博客特殊類別的所有條目,該類別可變)
Feed類必須繼承django.contrib.syndication.feeds.Feed,它們可以在你的代碼樹的任何位置
簡單的例子
這個(gè)簡單的例子來自于chicagocrime.org,描述最近5項(xiàng)新聞條目的feed:
- from django.contrib.syndication.feeds import Feed
- from chicagocrime.models import NewsItem
- class LatestEntries(Feed):
- title = "Chicagocrime.org site news"
- link = "/sitenews/"
- description = "Updates on changes and additions to chicagocrime.org."
- def items(self):
- return NewsItem.objects.order_by('-pub_date')[:5]
這里需要注意的重要事情:
1,這個(gè)類繼承django.contrib.syndication.feeds.Feed
2,title,link和description對應(yīng)標(biāo)準(zhǔn)的RSS(title),(link)和(description)元素
3,items()是簡單的返回在feed中作為(item)元素的對象列表的方法,盡管這個(gè)例子使用Django的數(shù)據(jù)庫API返回
NewsItem對象,items()不一定必須返回模型實(shí)例
你可以通過使用Django模型得到一些功能,但是items()可以返回任何你想要類型的對象
只有另一個(gè)更多的步驟,在一個(gè)RSS feed里,每個(gè)(item)有一個(gè)(title),(link)和(description),我們需要告訴框架
把哪些數(shù)據(jù)放到那些元素中
4,為了指定(title)和(description)的內(nèi)容,創(chuàng)建叫feeds/latest_title.html和feeds/latest_description.html的
Django模板(參考第4章),latest是給定feed的URL配置里指定的slug
注意.html擴(kuò)展名是必需的
RSS系統(tǒng)為每個(gè)條目渲染該模板,并傳遞兩個(gè)模板context變量:
obj
當(dāng)前對象(在items()里返回的對象里的一個(gè))
site
一個(gè)顯示當(dāng)前站點(diǎn)的django.models.core.sites.Site對象,它對{{ site.domain }}或者{{ site.name }}有用
如果你不為title或description創(chuàng)建模板,框架將默認(rèn)使用模板"{{ obj }}",對象的普通的字符串展示
你也可以通過指定title_template和description_template作為你的Feed類的屬性來改變這兩個(gè)模板的名字
5,為了指定(link)的內(nèi)容,你有兩個(gè)選擇,對items()的每個(gè)條目,Django首先嘗試執(zhí)行對象的get_absolute_url()方法
如果該方法不存在,則嘗試調(diào)用Feed類的item_link()方法,并把該對象本身作為參數(shù)item傳遞過去
6,對于上面的LatestEntries例子,我們可以有一些簡單的feed模板,latest_title.html包含:
- {{ obj.title }}
latest_description.html包含:
- {{ obj.description }}
這簡直太簡單了...
復(fù)雜的例子
框架也通過參數(shù)提供更復(fù)雜的feeds
例如,chicagocrime.org提供一個(gè)最近在Chicago每個(gè)警察打擊的犯罪的RSS feed,為每個(gè)警察打擊的犯罪創(chuàng)建單獨(dú)的
Feed類是很愚蠢的,這將違反DRY(Don't Repeat Yourself)原則并把數(shù)據(jù)和編程邏輯耦合
聚合框架讓你構(gòu)建基于feed的URL信息輸出items的通用feeds
在chicagocrime.org,警察打擊feeds可以像這樣通過URL訪問:
/rss/beats/0613/,返回0613打擊的最近犯罪
/rss/beats/1424/,返回1424打擊的最近犯罪
這里的slug是"beats",聚合框架查看slug后面另外的URL,0613和1424,并可以告訴它那些URL表示什么,以及它們怎樣
影響feed中哪些條目被發(fā)表
一個(gè)例子將把事情解釋清楚,這里是那些打擊專有的feeds的代碼:
- from django.core.exceptions import ObjectDoesNotExist
- class BeatFeed(Feed):
- def get_object(self, bits):
- # In case of "/rss/beats/0613/foo/bar/baz/", or other such
- # clutter, check that bits has only one member.
- if len(bits) != 1:
- raise ObjectDoesNotExist
- return Beat.objects.get(beat__exact=bits[0])
- def title(self, obj):
- return "Chicagocrime.org: Crimes for beat %s" % obj.beat
- def link(self, obj):
- return obj.get_absolute_url()
- def description(self, obj):
- return "Crimes recently reported in police beat %s" % obj.beat
- def items(self, obj):
- crimes = Crime.objects.filter(beat__id__exact=obj.id)
- return crimes.order_by('-crime_date')[:30]
這里是RSS框架遵循的基本算法,給定這個(gè)類和一個(gè)請求到/rss/beats/0613/:
1,框架得到/rss/beats/0613/的URL并注意到在slug后面有一個(gè)額外的URL片段,則它通過斜線字符("/")把后面的字符串
分隔開然后調(diào)用Feed類的get_object()方法并把片段傳遞過去
這里的片段是['0613'],對于/rss/beats/0613/foo/bar/的請求,片段則為['0613', 'foo', 'bar']
2,get_object()負(fù)責(zé)返回從給定片段得到給定的打擊
在這里,它使用Django數(shù)據(jù)庫API來查詢打擊,注意如果給定非法參數(shù)的話get_object()應(yīng)該觸發(fā)
django.core.exceptions.ObjectDoesNotExist異常,Beat.objects.get()調(diào)用沒有try/except包圍,因?yàn)闆]必要,
這個(gè)方法在失敗時(shí)觸發(fā)Beat.DoesNotExist,而Beat.DoesNotExist是ObjectDoesNotExist的子類,在get_object()里觸發(fā)
ObjectDoesNotExist異常告訴Django對該請求產(chǎn)生404錯(cuò)誤
3,為了生成feed的(title),(link)和(description),Django使用title(),link()和description()方法,在上個(gè)例子
中,它們是簡單的字符串類屬性,但是這個(gè)例子說明它們可以是字符串或者方法,對title,link和description中的任
一個(gè),Django遵循這個(gè)算法:
首先,它嘗試調(diào)用一個(gè)方法,傳遞obj參數(shù),這里obj是get_object()返回的對象
失敗的話,它嘗試調(diào)用一個(gè)沒有參數(shù)的方法
再失敗的話,它使用類屬性
4,最后,注意這個(gè)例子中的items()也需要obj參數(shù),items的算法和上一步描述的一樣,它嘗試items(obj),然后是
items(),最后是一個(gè)items類屬性(它應(yīng)該是一個(gè)列表)
Feed類所有方法和屬性的完整文檔一直可以從Django官方文檔得到
參看http://www.djangoproject.com/documentation/syndication/
指定feed類型
默認(rèn)框架使用RSS2.0生成feeds,這可以通過在你的Feed類添加feed_type屬性來更改:
- from django.utils.feedgenerator import Atom1Feed
- class MyFeed(Feed):
- feed_type = Atom1Feed
注意你設(shè)置feed_type為一個(gè)類對象,而不是一個(gè)實(shí)例,當(dāng)前可以得到的feed類型為:
Feed class Format
django.utils.feedgenerator.Rss201rev2Feed RSS 2.01(default).
django.utils.feedgenerator.RssUser1and091Feed RSS 0.91.
django.utils.feedgenerator.Atom1Feed Atom 1.0.
封裝
為了指定封裝,如那些用來創(chuàng)建podcast feeds的,使用item_enclosure_url,item_enclosure_length和
item_enclosure_mime_type鉤子,例如:
- from myproject.models import Song
- class MyFeedWithEnclosures(MyFeed):
- title = "Example feed with enclosures"
- link = "/feeds/example-with-enclosures/"
- def items(self):
- return Song.objects.all()[:30]
- def item_enclosure_url(self, item):
- return item.song_url
- def item_enclosure_length(self, item):
- return item.song_length
- item_enclosure_mime_type = "audio/mpeg"
當(dāng)然這個(gè)假設(shè)你已經(jīng)用song_url域和song_length域(即bytes表示的size)創(chuàng)建了Song對象
語言
聚合框架創(chuàng)建的Feeds自動(dòng)包含合適的(language)標(biāo)簽(RSS 2.0)或者xml:lang屬性(Atom)
它直接來自于你的LANGUAGE_CODE設(shè)置
URL
link方法/屬性可以返回一個(gè)絕對URL(例如"/blog/")或者一個(gè)具有完整域名和協(xié)議的URL
(例如"http://www.example.com/blog/"),如果link不返回域名,則聚合框架將根據(jù)你的SITE_ID設(shè)置插入當(dāng)前站點(diǎn)的域名
分別發(fā)布Atom和RSS feeds
一些開發(fā)者喜歡讓他們的feeds的Atom和RSS版本都可用,使用Django很容易做這個(gè):只需創(chuàng)建你的feed類的子類并設(shè)置
feed_type為不同的東西,然后更新你的URL配置來添加額外的版本,這里是一個(gè)完整的例子:
- from django.contrib.syndication.feeds import Feed
- from chicagocrime.models import NewsItem
- from django.utils.feedgenerator import Atom1Feed
- class RssSiteNewsFeed(Feed):
- title = "Chicagocrime.org site news"
- link = "/sitenews/"
- description = "Updates on changes and additions to chicagocrime.org."
- def items(self):
- return NewsItem.objects.order_by('-pub_date')[:5]
- class AtomSiteNewsFeed(RssSiteNewsFeed):
- feed_type = Atom1Feed
然后相應(yīng)的URL配置:
- from django.conf.urls.defaults import *
- from myproject.feeds import RssSiteNewsFeed, AtomSiteNewsFeed
- feeds = {
- 'rss': RssSiteNewsFeed,
- 'atom': AtomSiteNewsFeed,
- }
- urlpatterns = patterns('',
- # ...
- (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
- {'feed_dict': feeds}),
- # ...
- )
sitemap框架
類似于聚合框架,Django也有一個(gè)高級的Sitemap生成框架
一個(gè)Sitemap是一個(gè)你的網(wǎng)站的XML文件,它告訴搜索引擎索索引你的頁面的更新頻率和你的站點(diǎn)某些頁面聯(lián)系到其它頁面
有多"重要",這個(gè)信息幫助搜索引擎索引你的站點(diǎn),參看http://www.sitemaps.org得到更多關(guān)于Sitemaps
Django的sitemap框架通過讓你用Python代碼表達(dá)這個(gè)信息來自動(dòng)生成這個(gè)XML文件,為了創(chuàng)建一個(gè)sitemap,你只需寫
一個(gè)Sitemap類并在你的URL配置里指向它
安裝
遵循下面的步驟來安裝sitemap app:
1,添加'django.contrib.sitemaps'到你的INSTALLED_APPS設(shè)置
2,確認(rèn)'django.template.loaders.app_directories.load_template_source'在你的TEMPLATE_LOADERS設(shè)置中
它默認(rèn)在里面,所以如果你改變了這個(gè)設(shè)置則你將只需更改這個(gè)
3,確認(rèn)你已經(jīng)安裝了sites框架(參考第15章)
注意,sitemap程序不會(huì)安裝任何數(shù)據(jù)庫表,它需要進(jìn)入INSTALLED_APPS的唯一的原因是為了讓load_template_source
模板載入器可以找到默認(rèn)的模板
初始化
為了在你的Django站點(diǎn)激活sitemap生成,把下面的內(nèi)容添加到你的URL配置里:
- (r'^sitemap.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps})
這會(huì)告訴Django當(dāng)一個(gè)客戶端訪問/sitemap.xml時(shí)構(gòu)建一個(gè)sitemap
sitemap文件名不重要,但是位置很重要,搜索引擎將只為當(dāng)前及以下的URL級別索引你的sitemap里的鏈接
例如,如果sitemap.xml存在于你的根目錄,它將引用你的站點(diǎn)的任何URL,如果sitemap存在于/content/sitemap.xml,
它將只引用以/content/開始的URL
sitemap使用一個(gè)額外的必需參數(shù){'sitemaps': sitemaps},sitemaps應(yīng)該是一個(gè)映射簡短的section標(biāo)簽(如blog或者
news)到它的Sitemap類(如BlogSitemap或者NewsSitemap)的字典,它可能也映射一個(gè)Sitemap類的實(shí)例
(如BlogSitemap(some_var))
Sitemap類
一個(gè)Sitemap類是一個(gè)表示你的sitemap一部分條目的簡單的Python類,例如,一個(gè)Sitemap類可以表示你的博客的所有
條目,而另一個(gè)可以表示你的日程表的所有的事件
最簡單的情況下,所有這些部分混合在一個(gè)sitemap.xml里,但是也可以使用框架生成一個(gè)sitemap索引并引用單獨(dú)的
sitemap文件,每個(gè)部分一個(gè)文件(參看下面的內(nèi)容)
Sitemap類必須繼承django.contrib.sitemaps.Sitemap,它們可以在你的代碼樹的任意位置
例如,讓我們假設(shè)你有一個(gè)博客系統(tǒng)和一個(gè)Entry模型,并且你想讓你的sitemap包含所有到你的單獨(dú)博客條目的鏈接
這里是你的sitemap類的樣子:
- from django.contrib.sitemaps import Sitemap
- from mysite.blog.models import Entry
- class BlogSitemap(Sitemap):
- changefreq = "never"
- priority = 0.5
- def items(self):
- return Entry.objects.filter(is_draft=False)
- def lastmod(self, obj):
- return obj.pub_date
在看過聚合框架之后,這將看起來非常熟悉:
1,changefreq和priority是對應(yīng)(changefreq)和(priority)元素的類屬性,它們可以作為方法來調(diào)用,例如lastmod
2,items()是簡單的返回對象列表的方法,返回的對象將根據(jù)sitemap屬性(location,lastmod,changefreq和priority)
傳遞給任何可調(diào)用的方法
3,lastmod應(yīng)該返回一個(gè)Python datetime對象
4,例子中沒有l(wèi)ocation方法,但是你可以為了指出你的對象的URL而提供它,默認(rèn)location()對每個(gè)對象調(diào)用
get_absolute_url()并返回結(jié)果
Sitemap方法/屬性
像Feed類一樣,Sitemap成員可以是方法或者屬性,參考"復(fù)雜的例子"得到更多關(guān)于它怎樣工作的信息
一個(gè)Sitemap類可以定義以下方法/屬性:
items(必需)
提供對象列表,框架不關(guān)心它們是什么類型的對象,關(guān)心的只是這些對象傳遞給location(),lastmod(),changefreq()
和priority()方法
location(可選)
對給定對象提供絕對的URL
這里"絕對的URL"表示不包含協(xié)議和域名的URL,例如:
Good:'/foo/bar/'
Bad:'example.com/foo/bar/'
Bad:'http://example.com/foo/bar/'
如果location沒有提供,框架將對items()返回的每個(gè)對象調(diào)用get_absolute_url()方法
lastmod(可選)
對象的"last modification"日期,是一個(gè)Python datetime對象
changefreq(可選)
對象改變的頻率,可能的值(Sitemaps規(guī)范所給)為:
'always'
'hourly'
'daily'
'weekly'
'monthly'
'yearly'
'never'
priority(可選)
建議的索引優(yōu)先級別,在0.0和1.0之間,一個(gè)頁面的默認(rèn)級別為0.5,參看sitemaps.org文檔來得到更多關(guān)于priority
捷徑
sitemap框架為通常的情況提供了一些方便類:
FlatPageSitemap
django.contrib.sitemaps.FlatPageSitemap類查看當(dāng)前站點(diǎn)定義的所有flat頁面并在sitemap里創(chuàng)建條目,這些條目只
包含location屬性,不包含lastmod,changefreq或priority,參考第15章來得到更多關(guān)于flat頁面
GenericSitemap
GenericSitemap類和你已經(jīng)有的任何generic views(參考第9章)工作
為了使用它,創(chuàng)建一個(gè)實(shí)例并傳遞你傳遞給generic views的同樣的info_dict,僅有的需求是這個(gè)字典有一個(gè)queryset
條目,它可能也有一個(gè)date_field條目來指定從queryset得到的對象的date域,它被用于生成的sitemap的lastmod屬性
你也可以傳遞priority和changefreq關(guān)鍵字參數(shù)到GenericSitemap構(gòu)造函數(shù)來為所有的URL指定這些屬性
這里是一個(gè)使用FlatPageSitemap和GenericSitemap的URL配置的例子(使用上面假定的Entry對象):
- from django.conf.urls.defaults import *
- from django.contrib.sitemaps import FlatPageSitemap, GenericSitemap
- from mysite.blog.models import Entry
- info_dict = {
- 'queryset': Entry.objects.all(),
- 'date_field': 'pub_date',
- }
- sitemaps = {
-  
安徽新華電腦學(xué)校專業(yè)職業(yè)規(guī)劃師為你提供更多幫助【在線咨詢】