The Django Book

Chapter 14: Other Contributed Subframeworks

绗崄鍥涚珷 闆嗘垚鐨勫瓙妗嗘灦

One of the many strengths of Python is its batteries included philosophy: when you install Python, it comes with a large standard library of packages that you can start using immediately, without having to download anything else. Django aims to follow this philosophy, and it includes its own standard library of add-ons useful for common Web development tasks. This chapter covers that collection of add-ons.

Python鏈変紬澶氫紭鐐癸紝鍏朵腑涔嬩竴灏辨槸鈥滃紑鏈哄嵆鐢ㄢ濆師鍒欙細瀹夎Python鐨勫悓鏃跺畨瑁呭ソ澶ч噺鐨勬爣鍑嗚蒋浠跺寘锛岃繖鏍 浣犲彲浠ョ珛鍗充娇鐢ㄨ屼笉鐢ㄨ嚜宸卞幓涓嬭浇銆侱jango涔熼伒寰繖涓師鍒欙紝瀹冨悓鏍峰寘鍚簡鑷繁鐨勬爣鍑嗗簱銆傝繖涓绔犲氨鏉ヨ 杩欎簺闆嗘垚鐨勫瓙妗嗘灦銆

The Django Standard Library

Django鏍囧噯搴

Djangos standard library lives in the package django.contrib . Within each subpackage is a separate piece of add-on functionality. These pieces are not necessarily related, but some django.contrib subpackages may require other ones.

Django鐨勬爣鍑嗗簱瀛樻斁鍦 django.contrib 鍖呬腑銆傛瘡涓瓙鍖呴兘鏄竴涓嫭绔嬬殑闄勫姞鍔熻兘鍖呫 瀹冧滑浜掔浉涔嬮棿涓鑸病鏈夊繀鐒剁殑鍏宠仈锛屼絾鏄湁浜 django.contrib 瀛愬寘鍙兘渚濊禆鍏朵粬鐨勫寘銆

Theres no hard requirement for the types of functionality in django.contrib . Some of the packages include models (and hence require you to install their database tables into your database), but others consist solely of middleware or template tags.

django.contrib 涓鍑芥暟鐨勭被鍨嬪苟娌℃湁寮哄埗瑕佹眰 銆傚叾涓竴浜涘寘涓甫鏈夋ā鍨嬶紙鍥犳闇瑕佷綘鍦ㄦ暟鎹簱涓畨瑁呭搴旂殑鏁版嵁琛級锛屼絾鍏跺畠涓浜涚敱鐙珛鐨勪腑闂翠欢鍙婃ā鏉挎爣绛剧粍鎴愩

The single characteristic the django.contrib packages have in common is this: if you were to remove the django.contrib package entirely, you could still use Djangos fundamental features with no problems. When the Django developers add new functionality to the framework, they use this rule of thumb in deciding whether the new functionality should live in django.contrib or elsewhere.

django.contrib 寮鍙戝寘鍏辨湁鐨勭壒鎬ф槸:灏辩畻浣犲皢鏁翠釜 django.contrib 寮鍙戝寘鍒犻櫎锛屼綘渚濈劧鍙互浣跨敤 Django 鐨勫熀纭鍔熻兘鑰屼笉浼氶亣鍒颁换浣曢棶棰樸傚綋 Django 寮鍙戣呭悜妗嗘灦澧炲姞鏂板姛鑳界殑鏃讹紝浠栦滑浼氫弗鏍兼牴鎹繖涓鏁欐潯鏉ュ喅瀹氭槸鍚︽妸鏂板姛鑳芥斁鍏 django.contrib 涓

django.contrib consists of these packages:

django.contrib 鐢变互涓嬪紑鍙戝寘缁勬垚锛

  • admin : The automatic admin site. See Chapters 6 and 18.

  • admin : 鑷姩鍖栫殑绔欑偣绠$悊宸ュ叿銆傝鏌ョ湅绗6绔犲拰绗18绔

  • auth : Djangos authentication framework. See Chapter 12.

  • auth : Django鐨勭敤鎴烽獙璇佹鏋躲傝鏌ョ湅绗12绔

  • comments : A comments application. This application is currently under heavy development and thus couldnt be covered fully in time for this books publication. Check the Django Web site for the latest information about the comments application.

  • comments : 涓涓瘎璁哄簲鐢紝鐩墠锛岃繖涓簲鐢ㄦ鍦ㄧ揣寮犵殑寮鍙戜腑锛屽洜姝ゅ湪鏈功鍑虹増鐨勬椂鍊欒繕涓嶈兘缁欏嚭涓涓畬鏁寸殑璇存槑锛屽叧浜庤繖涓簲鐢ㄧ殑鏇村淇℃伅璇峰弬瑙丏jango鐨勫畼鏂圭綉绔.

  • contenttypes : A framework for hooking into types of content, where each installed Django model is a separate content type. This framework is used internally by other contrib applications and is mostly intended for very advanced Django developers. Those developers should find out more about this application by reading the source code in django/contrib/contenttypes/ .

  • contenttypes : 杩欐槸涓涓敤浜庢枃妗g被鍨嬮挬瀛愮殑妗嗘灦锛屾瘡涓畨瑁呯殑Django妯″潡浣滀负涓绉嶇嫭绔嬬殑鏂囨。绫诲瀷銆傝繖涓鏋朵富瑕佸湪Django鍐呴儴琚叾浠栧簲鐢ㄤ娇鐢紝瀹冧富瑕侀潰鍚慏jango鐨勯珮绾у紑鍙戣呫傚彲浠ラ氳繃闃呰婧愮爜鏉ヤ簡瑙e叧浜庤繖涓鏋剁殑鏇村淇℃伅锛屾簮鐮佺殑浣嶇疆鍦 django/contrib/contenttypes/ .

  • csrf : Protection against Cross-Site Request Forgery (CSRF). See the later section titled CSRF Protection.

  • csrf : 杩欎釜妯″潡鐢ㄦ潵闃插尽璺ㄧ珯璇锋眰浼(CSRF).鍙傝鍚庨潰鏍囬涓”CSRF 闃插尽”鐨勫皬鑺傘

  • flatpages : A framework for managing simple flat HTML content in a database. See the later section titled Flatpages.

  • flatpages : 涓涓湪鏁版嵁搴撲腑绠$悊鍗曚竴HTML鍐呭鐨勬ā鍧楋紝鍙傝鍚庨潰鏍囬涓衡淔latpages鈥濈殑灏忚妭銆

  • humanize : A set of Django template filters useful for adding a human touch to data. See the later section titled Humanizing Data.

  • humanize : 涓绯诲垪 Django 妯″潡杩囨护鍣紝鐢ㄤ簬澧炲姞鏁版嵁鐨勪汉鎬у寲銆傚弬闃呯◢鍚庣殑绔犺妭銆婁汉鎬у寲鏁版嵁銆嬨

  • markup : A set of Django template filters that implement a number of common markup languages. See the later section titled Markup Filters.

  • markup : 涓绯诲垪鐨 Django 妯℃澘杩囨护鍣紝鐢ㄤ簬瀹炵幇涓浜涘父鐢ㄦ爣璁拌瑷銆傚弬闃呭悗缁珷鑺傘婃爣璁拌繃婊ゅ櫒銆嬨

  • redirects : A framework for managing redirects. See the later section titled Redirects.

  • redirects : 鐢ㄦ潵绠$悊閲嶅畾鍚戠殑妗嗘灦銆傚弬瑙佸悗闈㈡爣棰樹负銆婇噸瀹氬悜銆嬬殑灏忚妭銆

  • sessions : Djangos session framework. See Chapter 12.

  • sessions : Django 鐨勪細璇濇鏋讹紝鍙傝12绔犮

  • sitemaps : A framework for generating sitemap XML files. See Chapter 11.

  • sitemaps : 鐢ㄦ潵鐢熸垚缃戠珯鍦板浘鐨 XML 鏂囦欢鐨勬鏋躲傚弬瑙 11 绔犮

  • sites : A framework that lets you operate multiple Web sites from the same database and Django installation. See the next section, Sites.

  • sites : 涓涓浣犲彲浠ュ湪鍚屼竴涓暟鎹簱涓 Django 瀹夎涓鐞嗗涓綉绔欑殑妗嗘灦銆傚弬瑙佷笅涓鑺傦細绔欑偣銆

  • syndication : A framework for generating syndication feeds in RSS and Atom. See Chapter 11.

  • syndication : 涓涓敤 RSS 鍜 Atom 鏉ョ敓鎴愯仛鍚堣闃呮簮鐨勭殑妗嗘灦銆傚弬闃呯 11 绔犮

The rest of this chapter goes into detail about each django.contrib package that we havent yet covered in this book.

鏈珷鎺ヤ笅鏉ュ皢璇︾粏鎻忚堪鍓嶉潰娌℃湁浠嬬粛杩囩殑 django.contrib 寮鍙戝寘鍐呭銆

Sites

澶氫釜绔欑偣

Djangos sites system is a generic framework that lets you operate multiple Web sites from the same database and Django project. This is an abstract concept, and it can be tricky to understand, so well start with a couple of scenarios where it would be useful.

Django 鐨勫绔欑偣绯荤粺鏄竴绉嶉氱敤妗嗘灦锛屽畠璁╀綘鍙互鍦ㄥ悓涓涓暟鎹簱鍜屽悓涓涓狣jango椤圭洰涓嬫搷浣滃涓綉绔欍傝繖鏄竴涓娊璞℃蹇碉紝鐞嗚В璧锋潵鍙兘鏈夌偣鍥伴毦锛屽洜姝ゆ垜浠粠鍑犱釜璁╁畠鑳芥淳涓婄敤鍦虹殑瀹為檯鎯呮櫙鍏ユ墜銆

Scenario 1: Reusing Data on Multiple Sites

鎯呮櫙1锛氬澶氫釜绔欑偣閲嶇敤鏁版嵁

As we explained in Chapter 1, the Django-powered sites LJWorld.com and Lawrence.com are operated by the same news organization: the Lawrence Journal-World newspaper in Lawrence, Kansas. LJWorld.com focuses on news, while Lawrence.com focuses on local entertainment. But sometimes editors want to publish an article on both sites.

姝e鎴戜滑鍦ㄧ涓绔犻噷鎵璁诧紝Django 鏋勫缓鐨勭綉绔 LJWorld.com 鍜 Lawrance.com 鏄敤鐢卞悓涓涓柊闂荤粍缁囨帶鍒剁殑锛氳偗钀ㄦ柉宸炲姵浼︽柉甯傜殑 鍔充鸡鏂棩鎶ヤ笘鐣 鎶ョ焊銆 LJWorld.com 涓昏鍋氭柊闂伙紝鑰 Lawrence.com 鍏虫敞鏈湴濞变箰銆傜劧鑰屾湁鏃讹紝缂栬緫鍙兘闇瑕佹妸涓绡囨枃绔犲彂甯冨埌 涓や釜 缃戠珯涓娿

The brain-dead way of solving the problem would be to use a separate database for each site and to require site producers to publish the same story twice: once for LJWorld.com and again for Lawrence.com. But thats inefficient for site producers, and its redundant to store multiple copies of the same story in the database.

瑙e喅姝ら棶棰樼殑姝昏剳绛嬫柟娉曞彲鑳芥槸浣跨敤姣忎釜绔欑偣鍒嗗埆浣跨敤涓嶅悓鐨勬暟鎹簱锛岀劧鍚庤姹傜珯鐐圭淮鎶よ呮妸鍚屼竴绡囨枃绔犲彂甯冧袱娆★細涓娆′负 LJWorld.com锛屽彟涓娆′负Lawrence.com銆備絾杩欏绔欑偣绠$悊鍛樻潵璇存槸浣庢晥鐜囩殑锛岃屼笖涓哄悓涓绡囨枃绔犲湪鏁版嵁搴撻噷淇濈暀澶氫釜鍓湰涔熸樉寰楀浣欍

The better solution? Both sites use the same article database, and an article is associated with one or more sites via a many-to-many relationship. The Django sites framework provides the database table to which articles can be related. Its a hook for associating data with one or more sites.

鏇村ソ鐨勮В鍐虫柟妗堬紵涓や釜缃戠珯鐢ㄧ殑鏄悓涓涓枃绔犳暟鎹簱锛屽苟灏嗘瘡涓绡囨枃绔犱笌涓涓垨澶氫釜绔欑偣鐢ㄥ瀵瑰鍏崇郴鍏宠仈璧锋潵銆侱jango 绔欑偣妗嗘灦鎻愪緵鏁版嵁搴撹杞藉摢浜涙枃绔犲彲浠ヨ鍏宠仈銆傚畠鏄竴涓妸鏁版嵁涓庝竴涓垨澶氫釜绔欑偣鍏宠仈璧锋潵鐨勯挬瀛愩

Scenario 2: Storing Your Site Name/Domain in One Place

鎯呮櫙2锛氭妸浣犵殑缃戠珯鍚嶇О/鍩熷瓨鍌ㄥ埌鍞竴鐨勪綅缃

LJWorld.com and Lawrence.com both have e-mail alert functionality, which lets readers sign up to get notifications when news happens. Its pretty basic: a reader signs up on a Web form, and he immediately gets an e-mail saying, Thanks for your subscription.

LJWorld.com 鍜 Lawrence.com 閮芥湁閭欢鎻愰啋鍔熻兘锛屼娇璇昏呮敞鍐屽悗鍙互鍦ㄦ柊闂诲彂鐢熷悗绔嬪嵆鏀跺埌閫氱煡銆傝繖鏄竴绉嶅畬缇庣殑鐨勬満鍒讹細鏌愯鑰呮彁浜や簡娉ㄥ唽琛ㄥ崟锛岀劧鍚庨┈涓婂氨鍙楀埌涓灏佸唴瀹规槸鈥滄劅璋㈡偍鐨勬敞鍐屸濈殑閭欢銆

It would be inefficient and redundant to implement this signup-processing code twice, so the sites use the same code behind the scenes. But the Thank you for your subscription notice needs to be different for each site. By using Site objects, we can abstract the thank-you notice to use the values of the current sites name (e.g., 'LJWorld.com' ) and domain (e.g., 'www.ljworld.com' ).

鎶婅繖涓敞鍐岃繃绋嬬殑浠g爜瀹炵幇涓ら亶鏄剧劧鏄綆鏁堛佸浣欑殑锛屽洜姝や袱涓珯鐐瑰湪鍚庡彴浣跨敤鐩稿悓鐨勪唬鐮併備絾鎰熻阿娉ㄥ唽鐨勯氱煡鍦ㄤ袱涓綉绔欎腑闇瑕佷笉鍚屻傞氳繃浣跨敤 Site 瀵硅薄锛屾垜浠氳繃浣跨敤褰撳墠绔欑偣鐨 name (渚嬪 'LJWorld.com' )鍜 domain (渚嬪 'www.ljworld.com' )鍙互鎶婃劅璋㈤氱煡鎶芥彁鍑烘潵銆

The Django sites framework provides a place for you to store the name and domain for each site in your Django project, which means you can reuse those values in a generic way.

Django 鐨勫绔欑偣妗嗘灦涓轰綘鎻愪緵浜嗕竴涓綅缃潵瀛樺偍 Django 椤圭洰涓瘡涓珯鐐圭殑 namedomain 锛岃繖鎰忓懗鐫浣犲彲浠ョ敤鍚屾牱鐨勬柟娉曟潵閲嶇敤杩欎簺鍊笺

How to Use the Sites Framework

濡備綍浣跨敤澶氱珯鐐规鏋

The sites framework is more a series of conventions than a framework. The whole thing is based on two simple concepts:

澶氱珯鐐规鏋朵笌鍏惰鏄竴涓鏋讹紝涓嶅璇存槸涓绯诲垪绾﹀畾銆傛墍鏈夌殑涓鍒囬兘鍩轰簬涓や釜绠鍗曠殑姒傚康锛

  • The Site model, found in django.contrib.sites , has domain and name fields.

  • 浣嶄簬 django.contrib.sitesSite 妯″瀷鏈 domainname 涓や釜瀛楁銆

  • The SITE_ID setting specifies the database ID of the Site object associated with that particular settings file.

  • SITE_ID 璁剧疆鎸囧畾浜嗕笌鐗瑰畾閰嶇疆鏂囦欢鐩稿叧鑱旂殑 Site 瀵硅薄涔嬫暟鎹簱 ID銆

How you use these two concepts is up to you, but Django uses them in a couple of ways automatically via simple conventions.

濡備綍杩愮敤杩欎袱涓蹇电敱浣犲喅瀹氾紝浣 Django 鏄氳繃鍑犱釜绠鍗曠殑绾﹀畾鑷姩浣跨敤鐨勩

To install the sites application, follow these steps:

瀹夎澶氱珯鐐瑰簲鐢ㄨ鎵ц浠ヤ笅鍑犱釜姝ラ锛

  1. Add 'django.contrib.sites' to your INSTALLED_APPS .

  1. 'django.contrib.sites' 鍔犲叆鍒 INSTALLED_APPS 涓

  1. Run the command manage.py syncdb to install the django_site table into your database.

  1. 杩愯 manage.py syncdb 鍛戒护灏 django_site 琛ㄥ畨瑁呭埌鏁版嵁搴撲腑銆

  1. Add one or more Site objects, either through the Django admin site or via the Python API. Create a Site object for each site/domain that this Django project powers.

  1. 閫氳繃 Django 绠$悊鍚庡彴鎴栭氳繃 Python API 娣诲姞涓涓垨鑰呭涓 ‘Site’ 瀵硅薄銆備负璇 Django 椤圭洰鏀拺鐨勬瘡涓珯锛堟垨鍩燂級鍒涘缓涓涓 Site 瀵硅薄銆

  1. Define the SITE_ID setting in each of your settings files. This value should be the database ID of the Site object for the site powered by that settings file.

  1. 鍦ㄦ瘡涓缃枃浠朵腑瀹氫箟涓涓 SITE_ID 鍙橀噺銆傝鍙橀噺鍊煎簲褰撴槸璇ヨ缃枃浠舵墍鏀拺鐨勭珯鐐逛箣 Site 瀵硅薄鐨勬暟鎹簱 ID 銆

The Sites Frameworks Capabilities

澶氱珯鐐规鏋剁殑鍔熻兘

The sections that follow describe the various things you can do with the sites framework.

涓嬮潰鍑犺妭璁茶堪鐨勬槸鐢ㄥ绔欑偣妗嗘灦鑳藉瀹屾垚鐨勫嚑椤瑰伐浣溿

Reusing Data on Multiple Sites
澶氫釜绔欑偣鐨勬暟鎹噸鐢

To reuse data on multiple sites, as explained in the first scenario, just create a ManyToManyField to Site in your models, for example:

姝e鍦ㄦ儏鏅竴涓墍瑙i噴鐨勶紝瑕佸湪澶氫釜绔欑偣闂撮噸鐢ㄦ暟鎹,浠呴渶鍦ㄦā鍨嬩腑涓 Site 娣诲姞涓涓 澶氬澶氬瓧娈 鍗冲彲锛屼緥濡傦細

from django.db import models
from django.contrib.sites.models import Site

class Article(models.Model):
    headline = models.CharField(maxlength=200)
    # ...
    sites = models.ManyToManyField(Site)

Thats the infrastructure you need to associate articles with multiple sites in your database. With that in place, you can reuse the same Django view code for multiple sites. Continuing the Article model example, heres what an article_detail view might look like:

杩欐槸鍦ㄦ暟鎹簱涓负澶氫釜绔欑偣杩涜鏂囩珷鍏宠仈鎿嶄綔鐨勫熀纭姝ラ銆傚湪閫傚綋鐨勪綅缃娇鐢ㄨ鎶鏈紝浣犲彲浠ュ湪澶氫釜绔欑偣涓噸澶嶄娇鐢ㄥ悓涓娈 Django 瑙嗗浘浠g爜銆傜户缁 Article 妯″瀷鑼冧緥锛屼笅闈㈡槸涓涓彲鑳界殑 article_detail 瑙嗗浘锛

from django.conf import settings

def article_detail(request, article_id):
    try:
        a = Article.objects.get(id=article_id, sites__id=settings.SITE_ID)
    except Article.DoesNotExist:
        raise Http404
    # ...

This view function is reusable because it checks the articles site dynamically, according to the value of the SITE_ID setting.

璇ヨ鍥炬柟娉曟槸鍙噸鐢ㄧ殑锛屽洜涓哄畠鏍规嵁 SITE_ID 璁剧疆鐨勫煎姩鎬佹鏌 articles 绔欑偣銆

For example, say LJWorld.coms settings file has a SITE_ID set to 1 , and Lawrence.coms settings file has a SITE_ID set to 2 . If this view is called when LJWorld.coms settings file is active, then it will limit the article lookup to articles in which the list of sites includes LJWorld.com.

渚嬪锛 LJWorld.coms 璁剧疆鏂囦欢涓湁鏈変釜 SITE_ID 璁剧疆涓 1 锛岃 Lawrence.coms 璁剧疆鏂囦欢涓湁涓 SITE_ID 璁剧疆涓 2 銆傚鏋滆瑙嗗浘鍦 LJWorld.coms 澶勪簬婵娲荤姸鎬佹椂琚皟鐢紝閭d箞瀹冨皢鎶婃煡鎵捐寖鍥村眬闄愪簬绔欑偣鍒楄〃鍖呮嫭 LJWorld.com 鍦ㄥ唴鐨勬枃绔犮

Associating Content with a Single Site
灏嗗唴瀹逛笌鍗曚竴绔欑偣鐩稿叧鑱

Similarly, you can associate a model to the Site model in a many-to-one relationship using ForeignKey .

鍚屾牱锛屼綘涔熷彲浠ヤ娇鐢 澶栭敭 鍦ㄥ瀵逛竴鍏崇郴涓皢涓涓ā鍨嬪叧鑱斿埌 Site 妯″瀷銆

For example, if an article is allowed on only a single site, you could use a model like this:

涓句緥鏉ヨ锛屽鏋滄煇绡囨枃绔犱粎浠呰兘澶熷嚭鐜板湪涓涓珯鐐逛笂锛屼綘鍙互浣跨敤涓嬮潰杩欐牱鐨勬ā鍨嬶細

from django.db import models
from django.contrib.sites.models import Site

class Article(models.Model):
    headline = models.CharField(maxlength=200)
    # ...
    site = models.ForeignKey(Site)

This has the same benefits as described in the last section.

杩欎笌鍓嶄竴鑺備腑浠嬬粛鐨勪竴鏍锋湁鐩娿

Hooking Into the Current Site from Views
浠庤鍥鹃挬鎸傚綋鍓嶇珯鐐

On a lower level, you can use the sites framework in your Django views to do particular things based on the site in which the view is being called, for example:

鍦ㄥ簳灞傦紝閫氳繃鍦 Django 瑙嗗浘涓娇鐢ㄥ绔欑偣妗嗘灦锛屼綘鍙互璁╄鍥炬牴鎹皟鐢ㄧ珯鐐逛笉鍚岃屽畬鎴愪笉鍚岀殑宸ヤ綔锛屼緥濡傦細

from django.conf import settings

def my_view(request):
    if settings.SITE_ID == 3:
        # Do something.
    else:
        # Do something else.

Of course, its ugly to hard-code the site IDs like that. A slightly cleaner way of accomplishing the same thing is to check the current sites domain:

褰撶劧锛屽儚閭f牱瀵圭珯鐐 ID 杩涜纭紪鐮佹槸姣旇緝闅剧湅鐨勩傜暐涓虹畝娲佺殑瀹屾垚鏂瑰紡鏄煡鐪嬪綋鍓嶇殑绔欑偣鍩燂細

from django.conf import settings
from django.contrib.sites.models import Site

def my_view(request):
    current_site = Site.objects.get(id=settings.SITE_ID)
    if current_site.domain == 'foo.com':
        # Do something
    else:
        # Do something else.

The idiom of retrieving the Site object for the value of settings.SITE_ID is quite common, so the Site models manager (Site.objects ) has a get_current() method. This example is equivalent to the previous one:

Site 瀵硅薄涓幏鍙 settings.SITE_ID 鍊肩殑鍋氭硶姣旇緝甯歌锛屽洜姝 Site 妯″瀷绠$悊鍣 (Site.objects ) 鍏峰涓涓 get_current() 鏂规硶銆備笅闈㈢殑渚嬪瓙涓庡墠涓涓槸绛夋晥鐨勶細

from django.contrib.sites.models import Site

def my_view(request):
    current_site = Site.objects.get_current()
    if current_site.domain == 'foo.com':
        # Do something
    else:
        # Do something else.

Note

娉ㄦ剰

In this final example, you dont have to import django.conf.settings .

鍦ㄨ繖涓渶鍚庣殑渚嬪瓙閲岋紝浣犱笉鐢ㄥ鍏 django.conf.settings

Getting the Current Domain for Display
鑾峰彇褰撳墠鍩熺敤浜庡憟鐜

For a DRY (Dont Repeat Yourself) approach to storing your sites name and domain name, as explained in Scenario 2: Storing Your Site Name/Domain in One Place, just reference the name and domain of the current Site object. For example:

姝e鎯呮櫙浜屼腑鎵瑙i噴鐨勯偅鏍凤紝瀵逛簬鍌ㄥ瓨绔欏悕鍜屽煙鍚嶇殑 DRY (Dont Repeat Yourself) 鏂规硶锛堝湪涓涓綅缃偍瀛樼珯鍚嶅拰鍩熷悕锛夋潵璇达紝鍙渶寮曠敤褰撳墠 Site 瀵硅薄鐨 namedomain 銆備緥濡傦細

from django.contrib.sites.models import Site
from django.core.mail import send_mail

def register_for_newsletter(request):
    # Check form values, etc., and subscribe the user.
    # ...
    current_site = Site.objects.get_current()
    send_mail('Thanks for subscribing to %s alerts' % current_site.name,
        'Thanks for your subscription. We appreciate it.\n\n-The %s team.' % current_site.name,
        'editor@%s' % current_site.domain,
        [user_email])
    # ...

Continuing our ongoing example of LJWorld.com and Lawrence.com, on Lawrence.com this e-mail has the subject line Thanks for subscribing to lawrence.com alerts. On LJWorld.com, the e-mail has the subject line Thanks for subscribing to LJWorld.com alerts. This same site-specific behavior is applied to the e-mails message body.

缁х画鎴戜滑姝e湪璁ㄨ鐨 LJWorld.com 鍜 Lawrence.com 渚嬪瓙锛屽湪Lawrence.com 璇ラ偖浠剁殑鏍囬琛屾槸鈥滄劅璋㈡敞鍐 Lawrence.com 鎻愰啋淇′欢鈥濄傚湪 LJWorld.com 锛岃閭欢鏍囬琛屾槸鈥滄劅璋㈡敞鍐 LJWorld.com 鎻愰啋淇′欢鈥濄傝繖绉嶇珯鐐瑰叧鑱旇涓烘柟寮忓閭欢淇℃伅涓讳綋涔熷悓鏍烽傜敤銆

An even more flexible (but more heavyweight) way of doing this would be to use Djangos template system. Assuming Lawrence.com and LJWorld.com have different template directories (TEMPLATE_DIRS ), you could simply delegate to the template system like so:

瀹屾垚杩欓」宸ヤ綔鐨勪竴绉嶆洿鍔犵伒娲伙紙浣嗛噸閲忕骇涔熸洿澶э級鐨勬柟娉曟槸浣跨敤 Django 鐨勬ā鏉跨郴缁熴傚亣瀹 Lawrence.com 鍜 LJWorld.com 鍚勮嚜鎷ユ湁涓嶅悓鐨勬ā鏉跨洰褰曪紙 TEMPLATE_DIRS 锛夛紝浣犲彲灏嗗伐浣滆交鏉惧湴杞氦缁欐ā鏉跨郴缁燂紝濡備笅鎵绀猴細

from django.core.mail import send_mail
from django.template import loader, Context

def register_for_newsletter(request):
    # Check form values, etc., and subscribe the user.
    # ...
    subject = loader.get_template('alerts/subject.txt').render(Context({}))
    message = loader.get_template('alerts/message.txt').render(Context({}))
    send_mail(subject, message, 'do-not-reply@example.com', [user_email])
    # ...

In this case, you have to create subject.txt and message.txt templates in both the LJWorld.com and Lawrence.com template directories. As mentioned previously, that gives you more flexibility, but its also more complex.

鏈緥涓紝浣犱笉寰椾笉鍦 LJWorld.com 鍜 Lawrence.com 鐨勬ā鏉跨洰褰曚腑閮藉垱寤轰竴浠 subject.txtmessage.txt 妯℃澘銆傛濡備箣鍓嶆墍璇达紝璇ユ柟娉曞甫鏉ヤ簡鏇村ぇ鐨勭伒娲绘э紝浣嗕篃甯︽潵浜嗘洿澶氬鏉傛с

Its a good idea to exploit the Site objects as much as possible to remove unneeded complexity and redundancy.

灏藉彲鑳藉鐨勫埄鐢 Site 瀵硅薄鏄噺灏戜笉蹇呰鐨勫鏉傘佸啑浣欏伐浣滅殑濂藉姙娉曘

Getting the Current Domain for Full URLs
鑾峰彇褰撳墠鍩熺殑瀹屾暣 URL

Djangos get_absolute_url() convention is nice for getting your objects URLs without the domain name, but in some cases you might want to display the full URL with http:// and the domain and everything for an object. To do this, you can use the sites framework. Heres a simple example:

Django 鐨 get_absolute_url() 绾﹀畾瀵逛笌鑾峰彇涓嶅甫鍩熷悕鐨勫璞 URL 闈炲父鐞嗘兂锛屼絾鍦ㄦ煇浜涙儏褰笅锛屼綘鍙兘鎯虫樉绀烘煇涓璞″甫鏈 http:// 鍜屽煙鍚嶄互鍙婃墍鏈夐儴鍒嗙殑瀹屾暣 URL 銆傝瀹屾垚姝ゅ伐浣滐紝浣犲彲浠ヤ娇鐢ㄥ绔欑偣妗嗘灦銆備笅闈㈡槸涓畝鍗曠殑渚嬪瓙锛

>>> from django.contrib.sites.models import Site
>>> obj = MyModel.objects.get(id=3)
>>> obj.get_absolute_url()
'/mymodel/objects/3/'
>>> Site.objects.get_current().domain
'example.com'
>>> 'http://%s%s' % (Site.objects.get_current().domain, obj.get_absolute_url())
'http://example.com/mymodel/objects/3/'

CurrentSiteManager

褰撳墠绔欑偣绠$悊鍣

If Site``s play a key role in your application, consider using the helpful ``CurrentSiteManager in your model(s). Its a model manager (see Appendix B) that automatically filters its queries to include only objects associated with the current Site .

濡傛灉 绔欑偣 鍦ㄤ綘鐨勫簲鐢ㄤ腑鎵紨寰堥噸瑕佺殑瑙掕壊锛岃鑰冭檻鍦ㄤ綘鐨勬ā鍨嬩腑浣跨敤鏂逛究鐨 CurrentSiteManager 銆傝繖鏄竴涓ā鍨嬬鐞嗗櫒锛堣闄勫綍B锛夛紝瀹冧細鑷姩杩囨护浣垮叾鍙寘鍚笌褰撳墠 绔欑偣 鐩稿叧鑱旂殑瀵硅薄銆

Use CurrentSiteManager by adding it to your model explicitly. For example:

閫氳繃鏄剧ず鍦板皢 CurrentSiteManager 鍔犲叆妯″瀷涓互浣跨敤瀹冦備緥濡傦細

from django.db import models
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager

class Photo(models.Model):
    photo = models.FileField(upload_to='/home/photos')
    photographer_name = models.CharField(maxlength=100)
    pub_date = models.DateField()
    site = models.ForeignKey(Site)
    objects = models.Manager()
    on_site = CurrentSiteManager()

With this model, Photo.objects.all() will return all Photo objects in the database, but Photo.on_site.all() will return only the Photo objects associated with the current site, according to the SITE_ID setting.

閫氳繃璇ユā鍨嬶紝 Photo.objects.all() 灏嗚繑鍥炴暟鎹簱涓墍鏈夌殑 Photo 瀵硅薄锛岃 Photo.on_site.all() 浠呮牴鎹 SITE_ID 璁剧疆杩斿洖涓庡綋鍓嶇珯鐐圭浉鍏宠仈鐨 Photo 瀵硅薄銆

In other words, these two statements are equivalent:

鎹㈣█涔嬶紝浠ヤ笅涓ゆ潯璇彞鏄瓑鏁堢殑锛

Photo.objects.filter(site=settings.SITE_ID)
Photo.on_site.all()

How did CurrentSiteManager know which field of Photo was the Site ? It defaults to looking for a field called site . If your model has a ForeignKey or ManyToManyField called something other than site , you need to explicitly pass that as the parameter to CurrentSiteManager . The following model, which has a field called publish_on , demonstrates this:

CurrentSiteManager 鏄浣曠煡閬 Photo 鐨勫摢涓瓧娈垫槸 Site 鍛紵缂虹渷鎯呭喌涓嬶紝瀹冧細鏌ユ壘涓涓彨鍋 site 鐨勫瓧娈点傚鏋滄ā鍨嬩腑鏈変釜 澶栭敭澶氬澶氬瓧娈 鍙仛 site 涔嬪 鐨勫悕瀛楋紝浣犲繀椤绘樉绀哄湴灏嗗畠浣滀负鍙傛暟浼犻掔粰 CurrentSiteManager 銆備笅闈㈢殑妯″瀷涓湁涓彨鍋 publish_on 鐨勫瓧娈碉紝濡備笅鎵绀猴細

from django.db import models
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager

class Photo(models.Model):
    photo = models.FileField(upload_to='/home/photos')
    photographer_name = models.CharField(maxlength=100)
    pub_date = models.DateField()
    publish_on = models.ForeignKey(Site)
    objects = models.Manager()
    on_site = CurrentSiteManager('publish_on')

If you attempt to use CurrentSiteManager and pass a field name that doesnt exist, Django will raise a ValueError .

濡傛灉璇曞浘浣跨敤 CurrentSiteManager 骞朵紶鍏ヤ竴涓笉瀛樺湪鐨勫瓧娈靛悕锛 Django 灏嗗紩鍙戜竴涓 ValueError 寮傚父銆

Note

娉ㄦ剰浜嬮」

Youll probably want to keep a normal (non-site-specific) Manager on your model, even if you use CurrentSiteManager . As explained in Appendix B, if you define a manager manually, then Django wont create the automatic objects = models.Manager() manager for you.

鍗充究鏄凡缁忎娇鐢ㄤ簡 CurrentSiteManager 锛屼綘涔熻杩樻兂鍦ㄦā鍨嬩腑鎷ユ湁涓涓甯哥殑锛堥潪绔欑偣鐩稿叧锛夌殑 绠$悊鍣 銆傛濡傚湪闄勫綍 B 涓墍瑙i噴鐨勶紝濡傛灉浣犳墜鍔ㄥ畾涔変簡涓涓鐞嗗櫒锛岄偅涔 Django 涓嶄細涓轰綘鍒涘缓鍏ㄨ嚜鍔ㄧ殑 objects = models.Manager() 绠$悊鍣ㄣ

Also, certain parts of Django namely, the Django admin site and generic views use whichever manager is defined first in the model, so if you want your admin site to have access to all objects (not just site-specific ones), put objects = models.Manager() in your model, before you define CurrentSiteManager .

鍚屾牱锛孌jango 鐨勭壒瀹氶儴鍒嗏斺斿嵆 Django 瓒呯骇绠$悊绔欑偣鍜岄氱敤瑙嗗浘鈥斺斾娇鐢ㄧ殑绠$悊鍣 棣栧厛 鍦ㄦā鍨嬩腑瀹氫箟锛屽洜姝ゅ鏋滃笇鏈涜秴绾х鐞嗙珯鐐硅兘澶熻闂墍鏈夊璞★紙鑰屼笉鏄粎浠呯珯鐐圭壒鏈夊璞★級锛岃浜庡畾涔 CurrentSiteManager 涔嬪墠鍦ㄦā鍨嬩腑鏀惧叆 objects = models.Manager()

How Django Uses the Sites Framework

Django濡備綍浣跨敤澶氱珯鐐规鏋

Although its not required that you use the sites framework, its strongly encouraged, because Django takes advantage of it in a few places. Even if your Django installation is powering only a single site, you should take a few seconds to create the site object with your domain and name , and point to its ID in your SITE_ID setting.

灏界骞朵笉鏄繀椤荤殑锛屾垜浠繕鏄己鐑堝缓璁娇鐢ㄥ绔欑偣妗嗘灦锛屽洜涓 Django 鍦ㄥ嚑涓湴鏂瑰埄鐢ㄤ簡瀹冦傚嵆浣垮彧鐢 Django 鏉ユ敮鎸佸崟涓綉绔欙紝浣犱篃搴旇鑺变竴鐐规椂闂寸敤 domainname 鏉ュ垱寤虹珯鐐瑰璞★紝骞跺皢 SITE_ID 璁剧疆鎸囧悜瀹冪殑 ID 銆

Heres how Django uses the sites framework:

浠ヤ笅璁茶堪鐨勬槸 Django 濡備綍浣跨敤澶氱珯鐐规鏋讹細

  • In the redirects framework (see the later section Redirects), each redirect object is associated with a particular site. When Django searches for a redirect, it takes into account the current SITE_ID .

  • 鍦ㄩ噸瀹氬悜妗嗘灦涓紙瑙佸悗闈㈢殑閲嶅畾鍚戜竴鑺傦級锛屾瘡涓涓噸瀹氬悜瀵硅薄閮戒笌涓涓壒瀹氱珯鐐瑰叧鑱斻傚綋 Django 鎼滅储閲嶅畾鍚戠殑鏃跺欙紝瀹冧細鑰冭檻褰撳墠鐨 SITE_ID

  • In the comments framework, each comment is associated with a particular site. When a comment is posted, its site is set to the current SITE_ID , and when comments are listed via the appropriate template tag, only the comments for the current site are displayed.

  • 鍦ㄦ敞鍐屾鏋朵腑锛屾瘡涓敞閲婇兘涓庣壒瀹氱珯鐐圭浉鍏炽傛瘡涓敞閲婅寮犺创鏃讹紝鍏 site 琚缃负褰撳墠鐨 SITE_ID 锛岃屽綋閫氳繃閫傚綋鐨勬ā鏉挎爣绛惧垪鍑烘敞閲婃椂锛屽彧鏈夊綋鍓嶇珯鐐圭殑娉ㄩ噴灏嗕細鏄剧ず銆

  • In the flatpages framework (see the later section Flatpages), each flatpage is associated with a particular site. When a flatpage is created, you specify its site , and the flatpage middleware checks the current SITE_ID in retrieving flatpages to display.

  • 鍦 flatpages 妗嗘灦涓 (鍙傝鍚庨潰鐨 Flatpages 涓鑺傦級锛屾瘡涓 flatpage 閮戒笌鐗瑰畾鐨勭珯鐐圭浉鍏宠仈銆傚垱寤 flatpage 鏃讹紝浣犻兘灏嗘寚瀹氬畠鐨 site 锛岃 flatpage 涓棿浠跺湪鑾峰彇 flatpage 浠ユ樉绀哄畠鐨勮繃绋嬩腑锛屽皢鏌ョ湅褰撳墠鐨 SITE_ID

  • In the syndication framework (see Chapter 11), the templates for title and description automatically have access to a variable {{ site }} , which is the Site object representing the current site. Also, the hook for providing item URLs will use the domain from the current Site object if you dont specify a fully qualified domain.

  • 鍦 syndication 妗嗘灦涓紙鍙傞槄绗 11 绔狅級锛 titledescription 鐨勬ā鏉胯嚜鍔ㄨ闂彉閲 {{ site }} 锛屽畠灏辨槸浠h〃褰撳墠鐫妗ㄧ殑 Site 瀵硅薄銆傝屼笖锛屽鏋滀綘涓嶆寚鍑轰竴涓畬鍏ㄥ悎鏍肩殑domain鐨勮瘽锛屾彁渚涚洰褰昒RLS鐨勯挬瀛愬皢浼氫娇鐢ㄥ綋鍓嶁淪ite鈥濆璞$殑domain銆

  • In the authentication framework (see Chapter 12), the django.contrib.auth.views.login view passes the current Site name to the template as {{ site_name }} .

  • 鍦ㄨ韩浠介獙璇佹鏋讹紙鍙傝绗 12 绔狅級涓紝 django.contrib.auth.views.login 瑙嗗浘灏嗗綋鍓 Site 鍚嶇О浣滀负 {{ site_name }} 浼犻掔粰妯℃澘銆

Flatpages

Flatpages - 绠鍗曢〉闈

Often youll have a database-driven Web application up and running, but youll need to add a couple of one-off static pages, such as an About page or a Privacy Policy page. It would be possible to use a standard Web server such as Apache to serve these files as flat HTML files, but that introduces an extra level of complexity into your application, because then you have to worry about configuring Apache, you have to set up access for your team to edit those files, and you cant take advantage of Djangos template system to style the pages.

灏界閫氬父鎯呭喌涓嬫绘槸寤洪犲拰杩愯鏁版嵁搴撻┍鍔ㄧ殑 Web 搴旂敤锛屼綘杩樻槸浼氶渶瑕佹坊鍔犱竴涓ゅ紶涓娆℃х殑闈欐侀〉闈紝渚嬪鈥滃叧浜庘濋〉闈紝鎴栬呪滈殣绉佺瓥鐣モ濋〉闈㈢瓑绛夈傚彲浠ョ敤鍍 Apache 杩欐牱鐨勬爣鍑哤eb鏈嶅姟鍣ㄦ潵澶勭悊杩欎簺闈欐侀〉闈紝浣嗗嵈浼氱粰搴旂敤甯︽潵涓浜涢澶栫殑澶嶆潅鎬э紝鍥犱负浣犲繀椤绘搷蹇冩庝箞閰嶇疆 Apache锛岃繕瑕佽缃潈闄愯鏁翠釜鍥㈤槦鍙互淇敼缂栬緫杩欎簺鏂囦欢锛岃屼笖浣犺繕涓嶈兘浣跨敤 Django 妯℃澘绯荤粺鏉ョ粺涓杩欎簺椤甸潰鐨勯鏍笺

The solution to this problem is Djangos flatpages application, which lives in the package django.contrib.flatpages . This application lets you manage such one-off pages via Djangos admin site, and it lets you specify templates for them using Djangos template system. It uses Django models behind the scenes, which means it stores the pages in a database, just like the rest of your data, and you can access flatpages with the standard Django database API.

杩欎釜闂鐨勮В鍐虫柟妗堟槸浣跨敤浣嶄簬 django.contrib.flatpages 寮鍙戝寘涓殑 Django 绠鍗曢〉闈紙flatpages锛夊簲鐢ㄧ▼搴忋傝搴旂敤璁╀綘鑳藉閫氳繃 Django 瓒呯骇绠$悊绔欑偣鏉ョ鐞嗚繖浜涗竴娆℃х殑椤甸潰锛岃繕鍙互璁╀綘浣跨敤 Django 妯℃澘绯荤粺鎸囧畾瀹冧滑浣跨敤鍝釜妯℃澘銆傚畠鍦ㄥ悗鍙颁娇鐢ㄤ簡 Django 妯″瀷锛屼篃灏辨槸璇村畠灏嗛〉闈㈠瓨鏀惧湪鏁版嵁搴撲腑锛屼綘涔熷彲浠ュ儚瀵瑰緟鍏朵粬鏁版嵁涓鏍风敤鏍囧噯 Django 鏁版嵁搴 API 瀛樺彇绠鍗曢〉闈€

Flatpages are keyed by their URL and site. When you create a flatpage, you specify which URL its associated with, along with which site(s) its on. (For more on sites, see the Sites section.)

绠鍗曢〉闈互瀹冧滑鐨 URL 鍜岀珯鐐逛负閿笺傚綋鍒涘缓绠鍗曢〉闈㈡椂锛屼綘鎸囧畾瀹冧笌鍝釜URL浠ュ強鍜屽摢涓珯鐐圭浉鍏宠仈 銆傦紙鏈夊叧绔欑偣鐨勬洿澶氫俊鎭紝璇锋煡闃呫婄珯鐐广嬩竴鑺傦級

Using Flatpages

浣跨敤绠鍗曢〉闈

To install the flatpages application, follow these steps:

瀹夎绠鍗曢〉闈㈠簲鐢ㄧ▼搴忓繀椤绘寜鐓т笅闈㈢殑姝ラ锛

  1. Add 'django.contrib.flatpages' to your INSTALLED_APPS . django.contrib.flatpages depends on django.contrib.sites , so make sure the both packages are in INSTALLED_APPS .

  1. 娣诲姞 'django.contrib.flatpages'INSTALLED_APPS 璁剧疆銆 django.contrib.flatpages 渚濊禆浜 django.contrib.sites , 鎵浠ョ‘淇濊繖涓や釜寮鍙戝寘閮藉寘鎷湪 INSTALLED_APPS 璁剧疆涓

  1. Add 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware' to your MIDDLEWARE_CLASSES setting.

  1. 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware' 娣诲姞鍒 MIDDLEWARE_CLASSES 璁剧疆涓

  1. Run the command manage.py syncdb to install the two required tables into your database.

  1. 杩愯 manage.py syncdb 鍛戒护鍦ㄦ暟鎹簱涓垱寤哄繀闇鐨勪袱涓〃銆

The flatpages application creates two tables in your database: django_flatpage and django_flatpage_sites . django_flatpage simply maps a URL to a title and bunch of text content. django_flatpage_sites is a many-to-many table that associates a flatpage with one or more sites.

绠鍗曢〉闈㈠簲鐢ㄧ▼搴忓湪鏁版嵁搴撲腑鍒涘缓涓や釜琛細 django_flatpagedjango_flatpage_sitesdjango_flatpage 鍙槸灏 URL 鏄犲皠鍒版爣棰樺拰涓娈垫枃鏈唴瀹广 django_flatpage_sites 鏄竴涓瀵瑰琛紝鐢ㄤ簬鍏宠仈鏌愪釜绠鍗曢〉闈互鍙婁竴涓垨澶氫釜绔欑偣銆

The application comes with a single FlatPage model, defined in django/contrib/flatpages/models.py . It looks like this:

璇ュ簲鐢ㄦ墍甯︽潵鐨 FlatPage 妯″瀷鍦 django/contrib/flatpages/models.py 杩涜瀹氫箟锛屽涓嬫墍绀猴細

from django.db import models
from django.contrib.sites.models import Site

class FlatPage(models.Model):
    url = models.CharField(maxlength=100)
    title = models.CharField(maxlength=200)
    content = models.TextField()
    enable_comments = models.BooleanField()
    template_name = models.CharField(maxlength=70, blank=True)
    registration_required = models.BooleanField()
    sites = models.ManyToManyField(Site)

Lets examine these fields one at a time:

璁╂垜浠愰」鐪嬬湅杩欎簺瀛楁鐨勫惈涔夛細

  • url : The URL at which this flatpage lives, excluding the domain name but including the leading slash (e.g., /about/contact/ ).

  • url : 璇ョ畝鍗曢〉闈㈡墍澶勭殑 URL锛屼笉鍖呮嫭鍩熷悕锛屼絾鏄寘鍚墠瀵兼枩鏉 (渚嬪 /about/contact/ )銆

  • title : The title of the flatpage. The framework doesnt do anything special with this. Its your responsibility to display it in your template.

  • title : 绠鍗曢〉闈㈢殑鏍囬銆傛鏋朵笉瀵瑰畠浣滀换浣曠壒娈婂鐞嗐傜敱浣犻氳繃妯℃澘鏉ユ樉绀哄畠銆

  • content : The content of the flatpage (i.e., the HTML of the page). The framework doesnt do anything special with this. Its your responsibility to display it in the template.

  • content : 绠鍗曢〉闈㈢殑鍐呭 (鍗 HTML 椤甸潰)銆傛鏋朵笉浼氬瀹冧綔浠讳綍鐗瑰埆澶勭悊銆傜敱浣犺礋璐d娇鐢ㄦā鏉挎潵鏄剧ず銆

  • enable_comments : Whether to enable comments on this flatpage. The framework doesnt do anything special with this. You can check this value in your template and display a comment form if needed.

  • enable_comments : 鏄惁鍏佽璇ョ畝鍗曢〉闈娇鐢ㄨ瘎璁恒傛鏋朵笉瀵规鍋氫换浣曠壒鍒鐞嗐備綘鍙湪妯℃澘涓鏌ヨ鍊煎苟鏍规嵁闇瑕佹樉绀鸿瘎璁虹獥浣撱

  • template_name : The name of the template to use for rendering this flatpage. This is optional; if its not given or if this template doesnt exist, the framework will fall back to the template flatpages/default.html .

  • template_name : 鐢ㄦ潵瑙f瀽璇ョ畝鍗曢〉闈㈢殑妯℃澘鍚嶇О銆傝繖鏄竴涓彲閫夐」锛涘鏋滄湭鎸囧畾妯℃澘鎴栬妯℃澘涓嶅瓨鍦紝绯荤粺浼氶鑰屼娇鐢ㄩ粯璁ゆā鏉 flatpages/default.html

  • registration_required : Whether registration is required for viewing this flatpage. This integrates with Djangos authentication/user framework, which is explained further in Chapter 12.

  • registration_required : 鏄惁娉ㄥ唽鐢ㄦ埛鎵嶈兘鏌ョ湅姝ょ畝鍗曢〉闈€傝璁剧疆椤归泦鎴愪簡 Djangos 楠岃瘉/鐢ㄦ埛妗嗘灦锛岃妗嗘灦浜庣鍗佷簩绔犺杩般

  • sites : The sites that this flatpage lives on. This integrates with Djangos sites framework, which is explained in the Sites section of this chapter.

  • sites : 璇ョ畝鍗曢〉闈㈡斁缃殑绔欑偣銆傝椤硅缃泦鎴愪簡 Django 澶氱珯鐐规鏋讹紝璇ユ鏋跺湪鏈珷鐨勩婂绔欑偣銆嬩竴鑺備腑鏈夋墍闃愯堪銆

You can create flatpages through either the Django admin interface or the Django database API. For more information on this, see the section Adding, Changing, and Deleting Flatpages.

浣犲彲浠ラ氳繃 Django 瓒呯骇绠$悊鐣岄潰鎴栬 Django 鏁版嵁搴 API 鏉ュ垱寤虹畝鍗曢〉闈€傝浜嗚В鏇村鍐呭锛岃鏌ラ槄銆婃坊鍔犮佷慨鏀瑰拰鍒犻櫎绠鍗曢〉闈€嬩竴鑺傘

Once youve created flatpages, FlatpageFallbackMiddleware does all of the work. Each time any Django application raises a 404 error, this middleware checks the flatpages database for the requested URL as a last resort. Specifically, it checks for a flatpage with the given URL with a site ID that corresponds to the SITE_ID setting.

涓鏃︾畝鍗曢〉闈㈠垱寤哄畬鎴愶紝 FlatpageFallbackMiddleware 灏嗗畬鎴愶紙鍓╀笅锛夋墍鏈夌殑宸ヤ綔銆傛瘡褰 Django 寮曞彂 404 閿欒锛屼綔涓虹粓鏋佹墜娈碉紝璇ヤ腑闂翠欢灏嗘牴鎹墍璇锋眰鐨 URL 妫鏌ュ钩椤甸潰鏁版嵁搴撱傜‘鍒囧湴璇达紝瀹冨皢浣跨敤鎵鎸囧畾鐨 URL浠ュ強 SITE_ID 璁剧疆瀵瑰簲鐨勭珯鐐 ID 鏌ユ壘涓涓畝鍗曢〉闈€

If it finds a match, it loads the flatpages template or flatpages/default.html if the flatpage has not specified a custom template. It passes that template a single context variable, flatpage , which is the flatpage object. It uses RequestContext in rendering the template.

濡傛灉鎵惧埌涓涓尮閰嶉」锛屽畠灏嗚浇鍏ヨ绠鍗曢〉闈㈢殑妯℃澘锛堝鏋滄病鏈夋寚瀹氱殑璇濓紝灏嗕娇鐢ㄩ粯璁ゆā鏉 flatpages/default.html 锛夈傚悓鏃讹紝瀹冩妸涓涓畝鍗曠殑涓婁笅鏂囧彉閲忊斺 flatpage 锛堜竴涓畝鍗曢〉闈㈠璞★級浼犻掔粰妯℃澘銆傚湪妯℃澘瑙f瀽杩囩▼涓紝瀹冨疄闄呯敤鐨勬槸 RequestContext

If FlatpageFallbackMiddleware doesnt find a match, the request continues to be processed as usual.

濡傛灉 FlatpageFallbackMiddleware 娌℃湁鎵惧埌鍖归厤椤癸紝璇ヨ姹傜户缁甯稿鐞嗐

Note

娉ㄦ剰

This middleware only gets activated for 404 (page not found) errors not for 500 (server error) or other error responses. Also note that the order of MIDDLEWARE_CLASSES matters. Generally, you can put FlatpageFallbackMiddleware at or near the end of the list, because its a last resort.

璇ヤ腑闂翠欢浠呭湪鍙戠敓 404 锛堥〉闈㈡湭鎵惧埌锛夐敊璇椂琚縺娲伙紝鑰屼笉浼氬湪 500 锛堟湇鍔″櫒閿欒锛夋垨鍏朵粬閿欒鍝嶅簲鏃惰婵娲汇傝繕瑕佹敞鎰忕殑鏄繀椤昏冭檻 MIDDLEWARE_CLASSES 鐨勯『搴忛棶棰樸傞氬父锛屼綘鍙互鎶 FlatpageFallbackMiddleware 鏀惧湪鍒楄〃鏈鍚庯紝鍥犱负瀹冩槸涓绉嶇粓鏋佹墜娈点

Adding, Changing, and Deleting Flatpages

娣诲姞銆佷慨鏀瑰拰鍒犻櫎绠鍗曢〉闈

You can add, change and delete flatpages in two ways:

鍙互鐢ㄤ袱绉嶆柟寮忓鍔犮佸彉鏇存垨鍒犻櫎绠鍗曢〉闈細

Via the Admin Interface
閫氳繃瓒呯骇绠$悊鐣岄潰

If youve activated the automatic Django admin interface, you should see a Flatpages section on the admin index page. Edit flatpages as you would edit any other object in the system.

濡傛灉宸茬粡婵娲讳簡鑷姩鐨 Django 瓒呯骇绠$悊鐣岄潰锛屼綘灏嗕細鍦ㄨ秴绾х鐞嗛〉闈㈢殑棣栭〉鐪嬪埌鏈変釜 Flatpages 鍖哄煙銆備綘鍙互鍍忕紪杈戠郴缁熶腑鍏跺畠瀵硅薄閭f牱缂栬緫绠鍗曢〉闈€

Via the Python API
閫氳繃 Python API

As described previously, flatpages are represented by a standard Django model that lives in django/contrib/flatpages/models.py . Hence, you can access flatpage objects via the Django database API, for example:

鍓嶉潰宸茬粡鎻愬埌锛岀畝鍗曢〉闈㈣〃鐜颁负 django/contrib/flatpages/models.py 涓殑鏍囧噯 Django 妯″瀷銆傚洜姝わ紝浣犲彲浠ラ氳繃 Django 鏁版嵁搴 API 鏉ュ瓨鍙栫畝鍗曢〉闈㈠璞★紝渚嬪锛

>>> from django.contrib.flatpages.models import FlatPage
>>> from django.contrib.sites.models import Site
>>> fp = FlatPage(
...     url='/about/',
...     title='About',
...     content='<p>About this site...</p>',
...     enable_comments=False,
...     template_name='',
...     registration_required=False,
... )
>>> fp.save()
>>> fp.sites.add(Site.objects.get(id=1))
>>> FlatPage.objects.get(url='/about/')
<FlatPage: /about/ -- About>

Using Flatpage Templates

浣跨敤绠鍗曢〉闈㈡ā鏉

By default, flatpages are rendered via the template flatpages/default.html , but you can override that for a particular flatpage with the template_name field on the FlatPage object.

缂虹渷鎯呭喌涓嬶紝绯荤粺浣跨敤妯℃澘 flatpages/default.html 鏉ヨВ鏋愮畝鍗曢〉闈紝浣嗕綘涔熷彲浠ラ氳繃璁惧畾 FlatPage 瀵硅薄鐨 template_name 瀛楁鏉ヨ鐩栫壒瀹氱畝鍗曢〉闈㈢殑妯℃澘銆

Creating the flatpages/default.html template is your responsibility. In your template directory, just create a flatpages directory containing a default.html file.

浣犲繀椤昏嚜宸卞垱寤 flatpages/default.html 妯℃澘銆傚彧闇瑕佸湪妯℃澘鐩綍鍒涘缓涓涓 flatpages 鐩綍锛屽苟鎶 default.html 鏂囦欢缃簬鍏朵腑銆

Flatpage templates are passed a single context variable, flatpage , which is the flatpage object.

绠鍗曢〉闈㈡ā鏉垮彧鎺ュ彈鏈変竴涓笂涓嬫枃鍙橀噺鈥斺 flatpage 锛屼篃灏辨槸璇ョ畝鍗曢〉闈㈠璞°

Heres a sample flatpages/default.html template:

浠ヤ笅鏄竴涓 flatpages/default.html 妯℃澘鑼冧緥:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
    "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>{{ flatpage.title }}</title>
</head>
<body>
{{ flatpage.content }}
</body>
</html>

Redirects

閲嶅畾鍚

Djangos redirects framework lets you manage redirects easily by storing them in a database and treating them as any other Django model object. For example, you can use the redirects framework to tell Django, Redirect any request to /music/ to /sections/arts/music/ . This comes in handy when you need to move things around on your site; Web developers should do whatever is necessary to avoid broken links.

閫氳繃灏嗛噸瀹氬悜瀛樺偍鍦ㄦ暟鎹簱涓苟灏嗗叾瑙嗕负 Django 妯″瀷瀵硅薄锛孌jango 閲嶅畾鍚戞鏋惰浣犺兘澶熻交鏉惧湴绠$悊瀹冧滑銆傛瘮濡傝锛屼綘鍙互閫氳繃閲嶅畾鍚戞鏋跺憡璇塂jango锛屾妸浠讳綍鎸囧悜 /music/ 鐨勮姹傞噸瀹氬悜鍒 /sections/arts/music/ 銆傚綋浣犻渶瑕佸湪绔欑偣涓Щ鍔ㄤ竴浜涗笢瑗挎椂锛岃繖椤瑰姛鑳藉氨娲句笂鐢ㄥ満浜嗏斺旂綉绔欏紑鍙戣呭簲璇ョ┓灏戒竴鍒囧姙娉曢伩鍏嶅嚭鐜板潖閾炬帴銆

Using the Redirects Framework

浣跨敤閲嶅畾鍚戞鏋

To install the redirects application, follow these steps:

瀹夎閲嶅畾鍚戝簲鐢ㄧ▼搴忓繀椤婚伒寰互涓嬫楠わ細

  1. Add 'django.contrib.redirects' to your INSTALLED_APPS .

  1. 'django.contrib.redirects' 娣诲姞鍒 INSTALLED_APPS 璁剧疆涓

  1. Add 'django.contrib.redirects.middleware.RedirectFallbackMiddleware' to your MIDDLEWARE_CLASSES setting.

  1. 'django.contrib.redirects.middleware.RedirectFallbackMiddleware' 娣诲姞鍒 MIDDLEWARE_CLASSES 璁剧疆涓

  1. Run the command manage.py syncdb to install the single required table into your database.

  1. 杩愯 manage.py syncdb 鍛戒护灏嗘墍闇鐨勮〃瀹夎鍒版暟鎹簱涓

manage.py syncdb creates a django_redirect table in your database. This is a simple lookup table with site_id , old_path , and new_path fields.

manage.py syncdb 鍦ㄦ暟鎹簱涓垱寤轰簡涓涓 django_redirect 琛ㄣ傝繖鏄竴涓畝鍗曠殑鏌ヨ琛紝鍙湁 site_idold_pathnew_path 涓変釜瀛楁銆

You can create redirects through either the Django admin interface or the Django database API. For more, see the section Adding, Changing, and Deleting Redirects.

浣犲彲浠ラ氳繃 Django 瓒呯骇绠$悊鐣岄潰鎴栬 Django 鏁版嵁搴 API 鏉ュ垱寤洪噸瀹氬悜銆傝浜嗚В鏇村淇℃伅锛岃鍙傞槄銆婂鍔犮佸彉鏇村拰鍒犻櫎閲嶅畾鍚戙嬩竴鑺傘

Once youve created redirects, the RedirectFallbackMiddleware class does all of the work. Each time any Django application raises a 404 error, this middleware checks the redirects database for the requested URL as a last resort. Specifically, it checks for a redirect with the given old_path with a site ID that corresponds to the SITE_ID setting. (See the earlier section Sites for more information on SITE_ID and the sites framework.) Then it follows these steps:

涓鏃﹀垱寤轰簡閲嶅畾鍚戯紝 RedirectFallbackMiddleware 绫诲皢瀹屾垚鎵鏈夌殑宸ヤ綔銆傛瘡褰 Django 搴旂敤寮曞彂涓涓 404 閿欒锛屼綔涓虹粓鏋佹墜娈碉紝璇ヤ腑闂翠欢灏嗕负鎵璇锋眰鐨 URL 鍦ㄩ噸瀹氬悜鏁版嵁搴撲腑杩涜鏌ユ壘銆傜‘鍒囧湴璇达紝瀹冨皢浣跨敤缁欏畾鐨 old_path 浠ュ強 SITE_ID 璁剧疆瀵瑰簲鐨勭珯鐐 ID 鏌ユ壘閲嶅畾鍚戣缃傦紙鏌ラ槄鍓嶉潰鐨勩婂绔欑偣銆嬩竴鑺傚彲浜嗚В鍏充簬 SITE_ID 鍜屽绔欑偣妗嗘灦鐨勬洿澶氱粏鑺傦級 鐒跺悗锛屽畠灏嗘墽琛屼互涓嬩袱涓楠わ細

  • If it finds a match, and new_path is not empty, it redirects to new_path .

  • 濡傛灉鎵惧埌浜嗗尮閰嶉」锛屽苟涓 new_path 闈炵┖锛屽畠灏嗛噸瀹氬悜鍒 new_path

  • If it finds a match, and new_path is empty, it sends a 410 (Gone) HTTP header and an empty (contentless) response.

  • 濡傛灉鎵惧埌浜嗗尮閰嶉」锛屼絾 new_path 涓虹┖锛屽畠灏嗗彂閫佷竴涓 410 (Gone) HTTP 澶翠俊鎭互鍙婁竴涓┖锛堟棤鍐呭锛夊搷搴斻

  • If it doesnt find a match, the request continues to be processed as usual.

  • 濡傛灉鏈壘鍒板尮閰嶉」锛岃璇锋眰灏嗗甯稿鐞嗐

The middleware only gets activated for 404 errors not for 500 errors or responses of any other status code.

璇ヤ腑闂翠欢浠呬负 404 閿欒婵娲伙紝鑰屼笉浼氫负 500 閿欒鎴栧叾浠栦换浣曠姸鎬佺爜鐨勫搷搴旀墍婵娲汇

Note that the order of MIDDLEWARE_CLASSES matters. Generally, you can put RedirectFallbackMiddleware toward the end of the list, because its a last resort.

娉ㄦ剰蹇呴』鑰冭檻 MIDDLEWARE_CLASSES 鐨勯『搴忋傞氬父锛屼綘鍙互灏 RedirectFallbackMiddleware 鏀剧疆鍦ㄥ垪琛ㄧ殑鏈鍚庯紝鍥犱负瀹冩槸涓绉嶇粓鏋佹墜娈点

Note

娉ㄦ剰

If youre using both the redirect and flatpage fallback middleware, consider which one (redirect or flatpage) youd like checked first. We suggest flatpages before redirects (thus putting the flatpage middleware before the redirect middleware), but you might feel differently.

濡傛灉鍚屾椂浣跨敤閲嶅畾鍚戝拰绠鍗曢〉闈㈠洖閫涓棿浠讹紝 蹇呴』鑰冭檻鍏堟鏌ュ叾涓殑鍝竴涓紙閲嶅畾鍚戞垨绠鍗曢〉闈級銆傛垜浠缓璁皢绠鍗曢〉闈㈡斁鍦ㄩ噸瀹氬悜涔嬪墠锛堝洜姝ゅ皢绠鍗曢〉闈腑闂翠欢鏀剧疆鍦ㄩ噸瀹氬悜涓棿浠朵箣鍓嶏級锛屼絾浣犲彲鑳芥湁涓嶅悓鎯虫硶銆

Adding, Changing, and Deleting Redirects

澧炲姞銆佸彉鏇村拰鍒犻櫎閲嶅畾鍚

You can add, change and delete redirects in two ways:

浣犲彲浠ヤ袱绉嶆柟寮忓鍔犮佸彉鏇村拰鍒犻櫎閲嶅畾鍚戯細

Via the Admin Interface
閫氳繃瓒呯骇绠$悊鐣岄潰

If youve activated the automatic Django admin interface, you should see a Redirects section on the admin index page. Edit redirects as you would edit any other object in the system.

濡傛灉宸茬粡婵娲讳簡鍏ㄨ嚜鍔ㄧ殑 Django 瓒呯骇绠$悊鐣岄潰锛屼綘搴旇鑳藉鍦ㄨ秴绾х鐞嗛椤电湅鍒伴噸瀹氬悜鍖哄煙銆傚彲浠ュ儚缂栬緫绯荤粺涓叾瀹冨璞′竴鏍风紪杈戦噸瀹氬悜銆

Via the Python API
閫氳繃 Python API

Redirects are represented by a standard Django model that lives in django/contrib/redirects/models.py . Hence, you can access redirect objects via the Django database API, for example:

django/contrib/redirects/models.py 涓殑涓涓爣鍑 Django 妯″瀷浠h〃浜嗛噸瀹氬悜銆傚洜姝わ紝浣犲彲浠ラ氳繃 Django 鏁版嵁搴 API 鏉ュ瓨鍙栭噸瀹氬悜瀵硅薄锛屼緥濡傦細

>>> from django.contrib.redirects.models import Redirect
>>> from django.contrib.sites.models import Site
>>> red = Redirect(
...     site=Site.objects.get(id=1),
...     old_path='/music/',
...     new_path='/sections/arts/music/',
... )
>>> red.save()
>>> Redirect.objects.get(old_path='/music/')
<Redirect: /music/ ---> /sections/arts/music/>

CSRF Protection

CSRF 闃叉姢

The django.contrib.csrf package protects against Cross-Site Request Forgery (CSRF).

django.contrib.csrf 寮鍙戝寘鑳藉闃叉閬彈璺ㄧ珯璇锋眰浼犳敾鍑 (CSRF).

CSRF, also known as session riding, is a Web site security exploit. It happens when a malicious Web site tricks a user into unknowingly loading a URL from a site at which that user is already authenticated, hence taking advantage of the users authenticated status. This can be a bit tricky to understand at first, so we walk through two examples in this section.

CSRF, 鍙堝彨杩涚▼璺宠浆锛屾槸涓绉嶇綉绔欏畨鍏ㄦ敾鍑绘妧鏈傚綋鏌愪釜鎭舵剰缃戠珯鍦ㄧ敤鎴锋湭瀵熻鐨勬儏鍐典笅灏嗗叾浠庝竴涓凡缁忛氳繃韬唤楠岃瘉鐨勭珯鐐硅楠楄嚦涓涓柊鐨 URL 鏃讹紝杩欑鏀诲嚮灏卞彂鐢熶簡锛屽洜姝ゅ畠鍙互鍒╃敤鐢ㄦ埛宸茬粡閫氳繃韬唤楠岃瘉鐨勭姸鎬併傚紑濮嬬殑鏃跺欙紝瑕佺悊瑙h繖绉嶆敾鍑绘妧鏈瘮杈冨洶闅撅紝鍥犳鎴戜滑鍦ㄦ湰鑺傚皢浣跨敤涓や釜渚嬪瓙鏉ヨ鏄庛

A Simple CSRF Example

涓涓畝鍗曠殑 CSRF 渚嬪瓙

Suppose youre logged in to a webmail account at example.com . This webmail site has a Log Out button that points to the URL example.com/logout that is, the only action you need to take in order to log out is to visit the page example.com/logout .

鍋囧畾浣犲凡缁忕櫥褰曞埌 example.com 鐨勭綉椤甸偖浠惰处鍙枫傝缃戦〉閭欢绔欑偣涓婃湁涓涓櫥鍑烘寜閽寚鍚戜簡 URL example.com/logout 锛屾崲鍙ヨ瘽璇达紝瑕佺櫥鍑虹殑璇濓紝闇瑕佸仛鐨勫敮涓鍔ㄤ綔灏辨槸璁块棶 URL 锛 example.com/logout

A malicious site can coerce you to visit the URL example.com/logout by including that URL as a hidden <iframe> on its own (malicious) page. Thus, if youre logged in to the example.com webmail account and visit the malicious page that has an <iframe> to example.com/logout , the act of visiting the malicious page will log you out from example.com .

閫氳繃鍦紙鎭舵剰锛夌綉椤典笂鐢ㄩ殣钘忎竴涓寚鍚 URL example.com/logout<iframe> ,鎭舵剰缃戠珯鍙互寮鸿揩浣犺闂 URL 銆傚洜姝わ紝濡傛灉浣犵櫥褰 example.com 鐨勭綉椤甸偖浠惰处鍙蜂箣鍚庯紝璁块棶浜嗗甫鏈夋寚鍚 example.com/logout<iframe> 鐨勬伓鎰忕珯鐐癸紝璁块棶璇ユ伓鎰忛〉闈㈢殑鍔ㄤ綔灏嗕娇浣犵櫥鍑 example.com

Clearly, being logged out of a webmail site against your will is not a terrifying breach of security, but this same type of exploit can happen to any site that trusts users, such as an online banking site or an e-commerce site.

璇氱劧锛屽浣犺岃█鐧诲嚭涓涓綉椤甸偖浠剁珯鐐瑰苟涓嶄細鏋勬垚澶氬ぇ鐨勫畨鍏ㄧ牬鍧忥紝浣嗗悓鏍风殑鏀诲嚮鍙兘鍙戠敓鍦 浠讳綍 淇′换鐢ㄦ埛鐨勭珯鐐逛箣涓婏紝姣斿鍦ㄧ嚎閾惰缃戠珯鎴栬呯數瀛愬晢鍔$綉绔欍

A More Complex CSRF Example

绋嶅井澶嶆潅涓鐐圭殑CSRF渚嬪瓙

In the previous example, example.com was partially at fault because it allowed a state change (i.e., logging the user out) to be requested via the HTTP GET method. Its much better practice to require an HTTP POST for any request that changes state on the server. But even Web sites that require POST for state-changing actions are vulnerable to CSRF.

鍦ㄤ笂涓涓緥瀛愪腑锛 example.com 搴旇璐熼儴鍒嗚矗浠伙紝鍥犱负瀹冨厑璁搁氳繃 HTTP GET 鏂规硶杩涜鐘舵佸彉鏇达紙鍗崇櫥鍏ュ拰鐧诲嚭锛夈傚鏋滃鏈嶅姟鍣ㄧ殑鐘舵佸彉鏇磋姹備娇鐢 HTTP POST 鏂规硶锛屾儏鍐靛氨濂藉緱澶氫簡銆備絾鏄紝鍗充究鏄己鍒惰姹備娇鐢 POST 鏂规硶杩涜鐘舵佸彉鏇存搷浣滀篃鏄撳彈鍒 CSRF 鏀诲嚮銆

Suppose example.com has upgraded its Log Out functionality so that its a <form> button that is requested via POST to the URL example.com/logout . Furthermore, the logout <form> includes this hidden field:

鍋囪 example.com 瀵圭櫥鍑哄姛鑳借繘琛屼簡鍗囩骇锛岀櫥鍑 <form> 鎸夐挳鏄氳繃涓涓寚鍚 URL example.com/logoutPOST 鍔ㄤ綔瀹屾垚锛屽悓鏃跺湪 <form> 涓姞鍏ヤ簡浠ヤ笅闅愯棌鐨勫瓧娈碉細

<input type="hidden" name="confirm" value="true" />

This ensures that a simple POST to the URL example.com/logout wont log a user out; in order for a user to log out, the user must request example.com/logout via POST and send the confirm POST variable with a value of 'true' .

杩欏氨纭繚浜嗙敤绠鍗曠殑 POSTexample.com/logout 涓嶄細璁╃敤鎴风櫥鍑猴紱瑕佽鐢ㄦ埛鐧诲嚭锛岀敤鎴峰繀椤婚氳繃 POSTexample.com/logout 鍙戦佽姹 骞朵笖 鍙戦佷竴涓间负 'true'POST 鍙橀噺銆

Well, despite the extra security, this arrangement can still be exploited by CSRF the malicious page just needs to do a little more work. Attackers can create an entire form targeting your site, hide it in an invisible <iframe> , and then use JavaScript to submit that form automatically.

灏界澧炲姞浜嗛澶栫殑瀹夊叏鏈哄埗锛岃繖绉嶈璁′粛鐒朵細閬埌 CSRF 鐨勬敾鍑烩斺旀伓鎰忛〉闈粎闇涓鐐圭偣鏀硅繘鑰屽凡銆傛敾鍑昏呭彲浠ラ拡瀵逛綘鐨勭珯鐐硅璁℃暣涓〃鍗曪紝骞跺皢鍏惰棌韬簬涓涓笉鍙鐨 <iframe> 涓紝鐒跺悗浣跨敤 Javascript 鑷姩鎻愪氦璇ヨ〃鍗曘

Preventing CSRF

闃叉 CSRF

How, then, can your site protect itself from this exploit? The first step is to make sure all GET requests are free of side effects. That way, if a malicious site includes one of your pages as an <iframe> , it wont have a negative effect.

閭d箞锛屾槸鍚﹀彲浠ヨ绔欑偣鍏嶅彈杩欑鏀诲嚮鍛紵绗竴姝ワ紝棣栧厛纭繚鎵鏈 GET 鏂规硶娌℃湁鍓綔鐢ㄣ傝繖鏍蜂互鏉ワ紝濡傛灉鏌愪釜鎭舵剰绔欑偣灏嗕綘鐨勯〉闈㈠寘鍚负 <iframe> 锛屽畠灏嗕笉浼氫骇鐢熻礋闈㈡晥鏋溿

That leaves POST requests. The second step is to give each POST <form> a hidden field whose value is secret and is generated from the users session ID. Then, when processing the form on the server side, check for that secret field and raise an error if it doesnt validate.

璇ユ妧鏈病鏈夎冭檻 POST 璇锋眰銆傜浜屾灏辨槸缁欐墍鏈 POST<form> 涓涓 闅愯棌瀛楁锛屽畠鐨勫兼槸淇濆瘑鐨勫苟鏍规嵁鐢ㄦ埛杩涚▼鐨 ID 鐢熸垚銆傝繖鏍凤紝浠庢湇鍔″櫒绔闂〃鍗曟椂锛屽彲浠ユ鏌ヨ淇濆瘑鐨勫瓧娈碉紝涓嶅惢鍚堟椂鍙互寮曞彂涓涓敊璇

This is exactly what Djangos CSRF prevention layer does, as explained in the sections that follow.

杩欐鏄 Django CSRF 闃叉姢灞傚畬鎴愮殑宸ヤ綔锛屾濡備笅闈㈢殑灏忚妭鎵浠嬬粛鐨勩

Using the CSRF Middleware
浣跨敤CSRF涓棿浠

The django.contrib.csrf package contains only one module: middleware.py . This module contains a Django middleware class, CsrfMiddleware , which implements the CSRF protection.

django.contrib.csrf 寮鍙戝寘鍙湁涓涓ā鍧楋細 middleware.py 銆傝妯″潡鍖呭惈浜嗕竴涓 Django 涓棿浠剁被鈥斺 CsrfMiddleware 锛岃绫诲疄鐜颁簡 CSRF 闃叉姢鍔熻兘銆

To activate this CSRF protection, add 'django.contrib.csrf.middleware.CsrfMiddleware' to the MIDDLEWARE_CLASSES setting in your settings file. This middleware needs to process the response after SessionMiddleware , so CsrfMiddleware must appear before SessionMiddleware in the list (because the response middleware is processed last-to-first). Also, it must process the response before the response gets compressed or otherwise mangled, so CsrfMiddleware must come after GZipMiddleware . Once youve added that to your MIDDLEWARE_CLASSES setting, youre done. See the section Order of MIDDLEWARE_CLASSES in Chapter 13 for more explanation.

鍦ㄨ缃枃浠朵腑灏 'django.contrib.csrf.middleware.CsrfMiddleware' 娣诲姞鍒 MIDDLEWARE_CLASSES 璁剧疆涓彲婵娲 CSRF 闃叉姢銆傝涓棿浠跺繀椤诲湪 SessionMiddleware 涔嬪悗 鎵ц锛屽洜姝ゅ湪鍒楄〃涓 CsrfMiddleware 蹇呴』鍑虹幇鍦 SessionMiddleware 涔嬪墠 锛堝洜涓哄搷搴斾腑闂翠欢鏄嚜鍚庡悜鍓嶆墽琛岀殑锛夈傚悓鏃讹紝瀹冧篃蹇呴』鍦ㄥ搷搴旇鍘嬬缉鎴栬В鍘嬩箣鍓嶅鍝嶅簲缁撴灉杩涜澶勭悊锛屽洜姝 CsrfMiddleware 蹇呴』鍦 GZipMiddleware 涔嬪悗鎵ц銆備竴鏃﹀皢瀹冩坊鍔犲埌 MIDDLEWARE_CLASSES 璁剧疆涓紝浣犲氨瀹屾垚浜嗗伐浣溿傚弬闃呯 13 绔犱腑鐨勩奙IDDLEWARE_CLASSES 鐨勯『搴忋嬩竴鑺備簡瑙f洿澶氳癄閲娿

In case youre interested, heres how CsrfMiddleware works. It does these two things:

濡傛灉鎰熷叴瓒g殑璇濓紝涓嬮潰鏄 CsrfMiddleware 鐨勫伐浣滄ā寮忋傚畠瀹屾垚浠ヤ笅涓ら」宸ヤ綔锛

  1. It modifies outgoing requests by adding a hidden form field to all POST forms, with the name csrfmiddlewaretoken and a value that is a hash of the session ID plus a secret key. The middleware does not modify the response if theres no session ID set, so the performance penalty is negligible for requests that dont use sessions.

  1. 瀹冧慨鏀瑰綋鍓嶅鐞嗙殑璇锋眰锛屽悜鎵鏈夌殑 POST 琛ㄥ崟澧炴坊涓涓殣钘忕殑琛ㄥ崟瀛楁锛屼娇鐢ㄥ悕绉版槸 csrfmiddlewaretoken 锛屽间负褰撳墠浼氳瘽 ID 鍔犱笂涓涓瘑閽ョ殑鏁e垪鍊笺傚鏋滄湭璁剧疆浼氳瘽 ID 锛岃涓棿浠跺皢 涓嶄細 淇敼鍝嶅簲缁撴灉锛屽洜姝ゅ浜庢湭浣跨敤浼氳瘽鐨勮姹傛潵璇存ц兘鎹熷け鏄彲浠ュ拷鐣ョ殑銆

  1. On all incoming POST requests that have the session cookie set, it checks that csrfmiddlewaretoken is present and correct. If it isnt, the user will get a 403 HTTP error. The content of the 403 error page is the message Cross Site Request Forgery detected. Request aborted.

  1. 瀵逛簬鎵鏈夊惈浼氳瘽 cookie 闆嗗悎鐨勪紶鍏 POST 璇锋眰锛屽畠灏嗘鏌ユ槸鍚﹀瓨鍦 csrfmiddlewaretoken 鍙婂叾鏄惁姝g‘銆傚鏋滀笉鏄殑璇濓紝鐢ㄦ埛灏嗕細鏀跺埌涓涓 403 HTTP 閿欒銆403 閿欒椤甸潰鐨勫唴瀹规槸娑堟伅锛氭娴嬪埌璺ㄧ珯浼璇锋眰銆傝姹傝缁堟銆傗

This ensures that only forms originating from your Web site can be used to POST data back.

璇ユ楠ょ‘淇濆彧鏈夋簮鑷綘鐨勭珯鐐圭殑琛ㄥ崟鎵嶈兘灏嗘暟鎹 POST 鍥炴潵銆

This middleware deliberately targets only HTTP POST requests (and the corresponding POST forms). As we explained, GET requests ought never to have side effects; its your own responsibility to ensure this.

璇ヤ腑闂翠欢鐗规剰鍙拡瀵 HTTP POST 璇锋眰锛堜互鍙婂搴旂殑 POST 琛ㄥ崟锛夈傚鎴戜滑鎵瑙i噴鐨勶紝姘歌繙涓嶅簲璇ュ洜涓轰娇鐢ㄤ簡 GET 璇锋眰鑰屼骇鐢熻礋闈㈡晥搴旓紝浣犲繀椤昏嚜宸辨潵纭繚杩欎竴鐐广

POST requests not accompanied by a session cookie are not protected, but they dont need to be protected, because a malicious Web site could make these kind of requests anyway.

鏈娇鐢ㄤ細璇 cookie 鐨 POST 璇锋眰鏃犳硶鍙楀埌淇濇姢锛屼絾瀹冧滑涔熶笉 闇瑕 鍙楀埌淇濇姢锛屽洜涓烘伓鎰忕綉绔欏彲鐢ㄤ换鎰忔柟娉曟潵鍒堕犺繖绉嶈姹傘

To avoid altering non-HTML requests, the middleware checks the responses Content-Type header before modifying it. Only pages that are served as text/html or application/xml+xhtml are modified.

涓轰簡閬垮厤杞崲闈 HTML 璇锋眰锛屼腑闂翠欢鍦ㄧ紪杈戝搷搴旂粨鏋滀箣鍓嶅瀹冪殑 Content-Type 澶存爣杩涜妫鏌ャ傚彧鏈夋爣璁颁负 text/htmlapplication/xml+xhtml 鐨勯〉闈㈡墠浼氳淇敼銆

Limitations of the CSRF Middleware
CSRF涓棿浠剁殑灞闄愭

CsrfMiddleware requires Djangos session framework to work. (See Chapter 12 for more on sessions.) If youre using a custom session or authentication framework that manually manages session cookies, this middleware will not help you.

CsrfMiddleware 鐨勮繍琛岄渶瑕 Django 鐨勪細璇濇鏋躲傦紙鍙傞槄绗 12 绔犱簡瑙f洿澶氬叧浜庝細璇濈殑鍐呭锛夊鏋滀綘浣跨敤浜嗚嚜瀹氫箟浼氳瘽鎴栬呰韩浠介獙璇佹鏋舵墜鍔ㄧ鐞嗕細璇 cookies锛岃涓棿浠跺皢甯笉涓婁綘鐨勫繖銆

If your application creates HTML pages and forms in some unusual way (e.g., if it sends fragments of HTML in JavaScript document.write statements), you might bypass the filter that adds the hidden field to the form. In this case, the form submission will always fail. (This happens because CsrfMiddleware uses a regular expression to add the csrfmiddlewaretoken field to your HTML before the page is sent to the client, and the regular expression sometimes cannot handle wacky HTML.) If you suspect this might be happening, just view the source in your Web browser to see whether csrfmiddlewaretoken was inserted into your <form> .

濡傛灉浣犵殑搴旂敤绋嬪簭浠ユ煇绉嶉潪甯歌鐨勬柟娉曞垱寤 HTML 椤甸潰锛堜緥濡傦細鍦 Javascript 鐨 document.write 璇彞涓彂閫 HTML 鐗囨锛夛紝浣犲彲鑳戒細缁曞紑浜嗗悜琛ㄥ崟娣诲姞闅愯棌瀛楁鐨勮繃婊ゅ櫒銆傚湪姝ゆ儏鍐典笅锛岃〃鍗曟彁浜ゆ案杩滄棤娉曟垚鍔熴傦紙杩欐槸鍥犱负鍦ㄩ〉闈㈣鍙戦佸埌瀹㈡埛绔箣鍓嶏紝 CsrfMiddleware 浣跨敤姝e垯琛ㄨ揪寮忓悜 HTML 涓坊鍔 csrfmiddlewaretoken 瀛楁锛岃屾湁鏃舵鍒欒〃杈惧紡鏃犳硶澶勭悊闈炲父瑙勭殑 HTML銆傦級濡傛灉浣犳鐤戝彂鐢熻繖绫讳簨鎯咃紝鍙渶鍦ㄦ祻瑙堝櫒涓煡鐪嬫簮鐮佺殑琛ㄥ崟涓槸鍚﹀凡缁忔彃鍏ヤ簡 csrfmiddlewaretoken

For more CSRF information and examples, visit http://en.wikipedia.org/wiki/CSRF.

鎯充簡瑙f洿澶氬叧浜 CSRF 鐨勪俊鎭拰渚嬪瓙鐨勮瘽锛屽彲浠ヨ闂 http://en.wikipedia.org/wiki/CSRF

Humanizing Data

浜烘у寲鏁版嵁

This application holds a set of Django template filters useful for adding a human touch to data. To activate these filters, add 'django.contrib.humanize' to your INSTALLED_APPS setting. Once youve done that, use {% load humanize %} in a template, and youll have access to the filters described in the following sections.

璇ュ簲鐢ㄧ▼搴忓寘鎷竴绯诲垪 Django 妯℃澘杩囨护鍣紝鐢ㄤ簬澧炲姞鏁版嵁鐨勪汉鎬у寲銆傝婵娲昏繖浜涜繃婊ゅ櫒锛屼粎闇灏 'django.contrib.humanize' 鍔犲叆鍒 INSTALLED_APPS 璁剧疆涓備竴鏃﹀畬鎴愯椤瑰伐浣滐紝鍦ㄦā鏉夸腑浣跨敤 {% load humanize %} 灏辫兘璁块棶鍚庣画灏忚妭涓杩扮殑杩囨护鍣ㄤ簡銆

apnumber

apnumber

For numbers 1 through 9, this filter returns the number spelled out. Otherwise, it returns the numeral. This follows Associated Press style.

瀵逛簬 1 鍒 9 鐨勬暟瀛楋紝璇ヨ繃婊ゅ櫒杩斿洖浜嗘暟瀛楃殑鎷煎啓褰㈠紡銆傚惁鍒欙紝瀹冨皢杩斿洖鏁板瓧銆傝繖閬靛惊鐨勬槸缇庤仈绀鹃鏍笺

Examples:

涓句緥锛

  • 1 becomes one.

  • 1 鍙樻垚 one 銆

  • 2 becomes two.

  • 2 鍙樻垚 two 銆

  • 10 becomes 10.

  • 10 鍙樻垚 10 銆

You can pass in either an integer or a string representation of an integer.

浣犲彲浠ヤ紶鍏ヤ竴涓暣鏁版垨鑰呰〃绀烘暣鏁扮殑瀛楃涓层

intcomma

intcomma

This filter converts an integer to a string containing commas every three digits.

璇ヨ繃婊ゅ櫒灏嗘暣鏁拌浆鎹负姣忎笁涓暟瀛楃敤涓涓楀彿鍒嗛殧鐨勫瓧绗︿覆銆

Examples:

渚嬪锛

  • 4500 becomes 4,500.

  • 4500 鍙樻垚 4,500 銆

  • 45000 becomes 45,000.

  • 45000 鍙樻垚 45,000 銆

  • 450000 becomes 450,000.

  • 450000 鍙樻垚 450,000 銆

  • 4500000 becomes 4,500,000.

  • 4500000 鍙樻垚 4,500,000 銆

You can pass in either an integer or a string representation of an integer.

浣犲彲浠ヤ紶鍏ユ暣鏁版垨鑰呰〃绀烘暣鏁扮殑瀛楃涓层

intword

intword

This filter converts a large integer to a friendly text representation. It works best for numbers over 1 million.

璇ヨ繃婊ゅ櫒灏嗕竴涓緢澶х殑鏁存暟杞崲鎴愬弸濂界殑鏂囨湰琛ㄧず鏂瑰紡銆傚畠瀵逛簬瓒呰繃涓鐧句竾鐨勬暟瀛楁渶濂界敤銆

Examples:

渚嬪锛

  • 1000000 becomes 1.0 million.

  • 1000000 鍙樻垚 1.0 million 銆

  • 1200000 becomes 1.2 million.

  • 1200000 鍙樻垚 1.2 million 銆

  • 1200000000 becomes 1.2 billion.

  • 1200000000 鍙樻垚 1.2 billion 銆

Values up to 1 quadrillion (1,000,000,000,000,000) are supported.

鏈澶ф敮鎸佷笉瓒呰繃涓鍗冪殑浜旀鏂癸紙1,000,000,000,000,000锛夈

You can pass in either an integer or a string representation of an integer.

浣犲彲浠ヤ紶鍏ユ暣鏁版垨鑰呰〃绀烘暣鏁扮殑瀛楃涓层

ordinal

ordinal

This filter converts an integer to its ordinal as a string.

璇ヨ繃婊ゅ櫒灏嗘暣鏁拌浆鎹负搴忔暟璇嶇殑瀛楃涓插舰寮忋

Examples:

渚嬪锛

  • 1 becomes 1st.

  • 1 鍙樻垚 1st 銆

  • 2 becomes 2nd.

  • 2 鍙樻垚 2nd 銆

  • 3 becomes 3rd.

  • 3 鍙樻垚 3rd 銆

You can pass in either an integer or a string representation of an integer.

浣犲彲浠ヤ紶鍏ユ暣鏁版垨鐫琛ㄧず鏁存暟鐨勫瓧绗︿覆銆

Markup Filters

鏍囪杩囨护鍣

The following collection of template filters implements common markup languages:

涓嬪垪妯℃澘杩囨护鍣ㄩ泦鍚堝疄鐜颁簡甯歌鐨勬爣璁拌瑷锛

In each case, the filter expects formatted markup as a string and returns a string representing the marked-up text. For example, the textile filter converts text that is marked up in Textile format to HTML:

姣忕鎯呭舰涓嬶紝杩囨护鍣ㄩ兘鏈熸湜瀛楃涓插舰寮忕殑鏍煎紡鍖栨爣璁帮紝骞惰繑鍥炶〃绀烘爣璁版枃鏈殑瀛楃涓层備緥濡傦細 textile 杩囨护鍣ㄦ妸浠 Textile 鏍煎紡鏍囪鐨勬枃鏈浆鎹负 HTML 銆

{% load markup %}
{{ object.content|textile }}

To activate these filters, add 'django.contrib.markup' to your INSTALLED_APPS setting. Once youve done that, use {% load markup %} in a template, and youll have access to these filters. For more documentation, read the source code in django/contrib/markup/templatetags/markup.py.

瑕佹縺娲昏繖浜涜繃婊ゅ櫒锛屼粎闇灏 'django.contrib.markup' 娣诲姞鍒 INSTALLED_APPS 璁剧疆涓備竴鏃﹀畬鎴愪簡璇ラ」宸ヤ綔锛屽湪妯℃澘涓娇鐢 {% load markup %} 灏辫兘浣跨敤杩欎簺杩囨护鍣ㄣ傝鎯虫帉鎻℃洿澶氫俊鎭殑璇濓紝鍙槄璇 django/contrib/markup/templatetags/markup.py. 鍐呯殑婧愪唬鐮併

Whats Next?

涓嬩竴姝ワ紵

Many of these contributed frameworks (CSRF, the auth system, etc.) do their magic by providing a piece of middleware . Middleware is essentially code that runs before and/or after every single request and can modify each request and response at will. Next, well discuss Djangos built-in middleware and explain how you can write your own.

杩欎簺缁ф壙妗嗘灦锛圕SRF銆佽韩浠介獙璇佺郴缁熺瓑绛夛級閫氳繃鎻愪緵 涓棿浠 鏉ュ疄鐜板叾濂囧鐨勫姛鑳姐傛湰璐ㄤ笂锛屼腑闂翠欢灏辨槸鍦ㄦ瘡涓姹備箣鍓嶆垨/鍜屼箣鍚庤繍琛岀殑浠g爜锛屽畠浠彲闅忔剰淇敼姣忎釜璇锋眰鎴栧搷搴斻傛帴涓嬫潵锛屾垜浠皢璁ㄨ Django 鐨勫唴寤轰腑闂翠欢锛屽苟瑙i噴濡備綍缂栧啓鑷繁鐨勪腑闂翠欢銆

Copyright 2006 Adrian Holovaty and Jacob Kaplan-Moss.
This work is licensed under the GNU Free Document License.
Hosting graciously provided by media temple
Chinese translate hosting by py3k.cn.