In Chapter 3, we explained the basics of Django view functions and URLconfs. This chapter goes into more detail about advanced functionality in those two pieces of the framework.
绗笁绔狅紝鎴戜滑璁插埌DJANGO鍩烘湰鐨勮鍥惧姛鑳藉拰URL閰嶇疆锛岃繖涓绔犲皢娑夊強鏇村缁嗚妭鍜岄珮绾у姛鑳姐
Theres nothing special about URLconfs like anything else in Django, theyre just Python code. You can take advantage of this in several ways, as described in the sections that follow.
psiOnM <a href=”http://nbrzcxnliggw.com/“>nbrzcxnliggw</a>, [url=http://nbeqcslpbjht.com/]nbeqcslpbjht[/url], [link=http://xmxroewwggzy.com/]xmxroewwggzy[/link], http://nabarnvmapgz.com/
Yfphr6 <a href=”http://wkchavkykyhr.com/“>wkchavkykyhr</a>, [url=http://muokhwblpfjl.com/]muokhwblpfjl[/url], [link=http://ploxqieojkeb.com/]ploxqieojkeb[/link], http://xhutfvdzimfx.com/
Consider this URLconf, which builds on the example in Chapter 3:
鐪嬩笅杩欎釜 URLconf锛屽畠鏄缓绔嬪湪绗笁绔犵殑渚嬪瓙涓:
from django.conf.urls.defaults import * from mysite.views import current_datetime, hours_ahead, hours_behind, now_in_chicago, now_in_london urlpatterns = patterns('', (r'^now/$', current_datetime), (r'^now/plus(\d{1,2})hours/$', hours_ahead), (r'^now/minus(\d{1,2})hours/$', hours_behind), (r'^now/in_chicago/$', now_in_chicago), (r'^now/in_london/$', now_in_london), )
As explained in Chapter 3, each entry in the URLconf includes its associated view function, passed directly as a function object. This means its necessary to import the view functions at the top of the module.
姝e绗笁绔犱腑鎵瑙i噴鐨勶紝鍦 URLconf 涓殑姣忎竴涓叆鍙e寘鎷簡瀹冩墍鑱旂郴鐨勮鍥惧嚱鏁帮紝鐩存帴浼犲叆浜嗕竴涓嚱鏁板璞°傝繖灏辨剰鍛崇潃闇瑕佸湪妯″潡寮濮嬪瀵煎叆瑙嗗浘鍑芥暟銆
But as a Django application grows in complexity, its URLconf grows, too, and keeping those imports can be tedious to manage. (For each new view function, you have to remember to import it, and the import statement tends to get overly long if you use this approach.) Its possible to avoid that tedium by importing the views module itself. This example URLconf is equivalent to the previous one:
浣嗛殢鐫 Django 搴旂敤鍙樺緱澶嶆潅锛屽畠鐨 URLconf 涔熷湪澧為暱锛屽苟涓旂淮鎶よ繖浜涘鍏ュ彲鑳戒娇寰楃鐞嗗彉楹荤儲銆(瀵规瘡涓柊鐨剉iew鍑芥暟锛屼綘涓嶅緱涓嶈浣忚瀵煎叆瀹冿紝骞朵笖濡傛灉閲囩敤杩欑鏂规硶瀵煎叆璇彞灏嗗彉寰楃浉褰撻暱銆)鏈夊彲鑳介氳繃瀵煎叆 views 妯″潡鏈韩鏉ラ伩鍏嶈繖涓夯鐑︺傝繖涓 URLconf 绀轰緥鍚屼笂涓涓槸绛変环鐨:
from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^now/$', views.current_datetime), (r'^now/plus(\d{1,2})hours/$', views.hours_ahead), (r'^now/minus(\d{1,2})hours/$', views.hours_behind), (r'^now/in_chicago/$', views.now_in_chicago), (r'^now/in_london/$', views.now_in_london), )
Django offers another way of specifying the view function for a particular pattern in the URLconf: you can pass a string containing the module name and function name rather than the function object itself. Continuing the ongoing example:
Django 杩樻彁渚涗簡鍙︿竴绉嶆柟娉曞彲浠ュ湪 URLconf 涓负鏌愪釜鐗瑰埆鐨勬ā寮忔寚瀹氳鍥惧嚱鏁帮細浣犲彲浠ヤ紶鍏ヤ竴涓寘鍚ā鍧楀悕鍜屽嚱鏁板悕鐨勫瓧绗︿覆锛岃屼笉鏄嚱鏁板璞℃湰韬傜户缁ず渚:
from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^now/$', 'mysite.views.current_datetime'), (r'^now/plus(\d{1,2})hours/$', 'mysite.views.hours_ahead'), (r'^now/minus(\d{1,2})hours/$', 'mysite.views.hours_behind'), (r'^now/in_chicago/$', 'mysite.views.now_in_chicago'), (r'^now/in_london/$', 'mysite.views.now_in_london'), )
(Note the quotes around the view names. Were using 'mysite.views.current_datetime' with quotes instead of mysite.views.current_datetime .)
(娉ㄦ剰瑙嗗浘鍚嶅墠鍚庣殑寮曞彿銆傚簲璇ヤ娇鐢ㄥ甫寮曞彿鐨 'mysite.views.current_datetime' 鑰屼笉鏄 mysite.views.current_datetime 銆)
Using this technique, its no longer necessary to import the view functions; Django automatically imports the appropriate view function the first time its needed, according to the string describing the name and path of the view function.
浣跨敤杩欎釜鎶鏈紝灏变笉蹇呭鍏ヨ鍥惧嚱鏁颁簡锛汥jango 浼氬湪绗竴娆¢渶瑕佸畠鏃跺鍏ュ悎閫傜殑瑙嗗浘鍑芥暟锛屾牴鎹瓧绗︿覆鎵鎻忚堪鐨勮鍥惧嚱鏁扮殑鍚嶅瓧鍜岃矾寰勩
A further shortcut you can take when using the string technique is to factor out a common view prefix. In our URLconf example, each of the view strings starts with 'mysite.views' , which is redundant to type. We can factor out that common prefix and pass it as the first argument to patterns() , like this:
褰撲娇鐢ㄥ瓧绗︿覆鎶鏈椂锛屼綘鍙互閲囩敤鏇寸畝鍖栫殑鏂瑰紡锛氭彁鍙栧嚭涓涓叕鍏辫鍥惧墠缂銆傚湪鎴戜滑鐨 URLconf 渚嬪瓙涓紝姣忎竴涓鍥惧瓧绗︿覆閮芥槸浠 'mysite.views' 寮濮嬬殑锛岄犳垚杩囧鐨勮緭鍏ャ傛垜浠彲浠ユ彁鍙栧嚭鍏叡鍓嶇紑鐒跺悗鎶婂畠浣滀负绗竴涓弬鏁颁紶缁 patterns() 锛屽:
from django.conf.urls.defaults import * urlpatterns = patterns('mysite.views', (r'^now/$', 'current_datetime'), (r'^now/plus(\d{1,2})hours/$', 'hours_ahead'), (r'^now/minus(\d{1,2})hours/$', 'hours_behind'), (r'^now/in_chicago/$', 'now_in_chicago'), (r'^now/in_london/$', 'now_in_london'), )
Note that you dont put a trailing dot ("." ) in the prefix, nor do you put a leading dot in the view strings. Django puts those in automatically.
娉ㄦ剰鏃笉瑕佸湪鍓嶇紑鍚庨潰璺熺潃涓涓偣鍙("." )锛屼篃涓嶈鍦ㄨ鍥惧瓧绗︿覆鍓嶉潰鏀句竴涓偣鍙枫 Django 浼氳嚜鍔ㄥ鐞嗗畠浠
With these two approaches in mind, which is better? It really depends on your personal coding style and needs.
鐗㈣杩欎袱绉嶆柟娉曪紝鍝鏇村ソ涓浜涘憿锛熻繖鍙栧喅浜庝綘鐨勪釜浜虹紪鐮佷範鎯拰闇瑕併
Advantages of the string approach are as follows:
UNF5vX <a href=”http://hdugwlkorxzw.com/“>hdugwlkorxzw</a>, [url=http://sbppygxqjdcj.com/]sbppygxqjdcj[/url], [link=http://icxfehixtpuo.com/]icxfehixtpuo[/link], http://tmihfbbxxydh.com/
Its more compact, because it doesnt require you to import the view functions.
N9gqns <a href=”http://wteejridtwke.com/“>wteejridtwke</a>, [url=http://lxotonbmgclb.com/]lxotonbmgclb[/url], [link=http://hkhsettjexoq.com/]hkhsettjexoq[/link], http://dlapxtivyork.com/
It results in more readable and manageable URLconfs if your view functions are spread across several different Python modules.
濡傛灉浣犵殑瑙嗗浘鍑芥暟瀛樺湪浜庡嚑涓笉鍚岀殑 Python 妯″潡鐨勮瘽锛屽畠鍙互浣垮緱 URLconf 鏇存槗璇诲拰绠$悊銆
Advantages of the function object approach are as follows:
WdAon8 <a href=”http://gnuhdlcakrdi.com/“>gnuhdlcakrdi</a>, [url=http://mkbdhjkqvlqt.com/]mkbdhjkqvlqt[/url], [link=http://rdpcyyxxithz.com/]rdpcyyxxithz[/link], http://rsbyearxigne.com/
It allows for easy wrapping of view functions. See the section Wrapping View Functions later in this chapter.
鏇村鏄撳瑙嗗浘鍑芥暟杩涜鍖呰(wrap)銆傚弬瑙佹湰绔犲悗闈㈢殑銆婂寘瑁呰鍥惧嚱鏁般嬩竴鑺傘
Its more Pythonic that is, its more in line with Python traditions, such as passing functions as objects.
鏇 Pythonic锛屾洿绗﹀悎 Python 鐨勪紶缁燂紝濡傛妸鍑芥暟褰撴垚瀵硅薄浼犻掋
Both approaches are valid, and you can even mix them within the same URLconf. The choice is yours.
涓や釜鏂规硶閮芥槸鏈夋晥鐨勶紝鐢氳嚦浣犲彲浠ュ湪鍚屼竴涓 URLconf 涓贩鐢ㄥ畠浠傚喅瀹氭潈鍦ㄤ綘銆
In practice, if you use the string technique, youll probably end up mixing views to the point where the views in your URLconf wont have a common prefix. However, you can still take advantage of the view prefix shortcut to remove duplication. Just add multiple patterns() objects together, like this:
鍦ㄥ疄璺典腑锛屽鏋滀綘浣跨敤瀛楃涓叉妧鏈紝鐗瑰埆鏄綋浣犵殑 URLconf 涓病鏈変竴涓叕鍏卞墠缂鏃讹紝浣犳渶缁堝彲鑳芥贩鍚堣鍥俱傜劧鑰岋紝浣犱粛鐒跺彲浠ュ埄鐢ㄨ鍥惧墠缂鐨勭畝渚挎柟寮忔潵鍑忓皯閲嶅銆傚彧瑕佸鍔犲涓 patterns() 瀵硅薄锛岃薄杩欐牱:
Old:
鏃х殑:
from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^/?$', 'mysite.views.archive_index'), (r'^(\d{4})/([a-z]{3})/$', 'mysite.views.archive_month'), (r'^tag/(\w+)/$', 'weblog.views.tag'), )
New:
鏂扮殑:
from django.conf.urls.defaults import * urlpatterns = patterns('mysite.views', (r'^/?$', 'archive_index'), (r'^(\d{4})/([a-z]{3})/$', 'archive_month'), ) urlpatterns += patterns('weblog.views', (r'^tag/(\w+)/$', 'tag'), )
All the framework cares about is that theres a module-level variable called urlpatterns . This variable can be constructed dynamically, as we do in this example.
鏁翠釜妗嗘灦鍏虫敞鐨勬槸瀛樺湪涓涓悕涓 urlpatterns 鐨勬ā鍧楃骇鍒殑鍙橀噺銆傝繖涓彉閲忓彲浠ュ姩鎬佹瀯寤猴紝姝e鏈緥涓垜浠墍鍋氱殑涓鏍枫
Speaking of constructing urlpatterns dynamically, you might want to take advantage of this technique to alter your URLconfs behavior while in Djangos debug mode. To do this, just check the value of the DEBUG setting at runtime, like so:
褰撹皥鍒板姩鎬佹瀯寤 urlpatterns 鏃讹紝浣犲彲鑳芥兂鍒╃敤杩欎竴鎶鏈紝鍦 Django 鐨勮皟璇曟ā寮忔椂锛屾潵淇敼 URLconf 鐨勮涓恒備负浜嗗仛鍒拌繖涓鐐癸紝鍙鍦ㄨ繍琛屾椂妫鏌 DEBUG 閰嶇疆椤圭殑鍊煎嵆鍙紝濡:
from django.conf.urls.defaults import* from django.conf import settings urlpatterns = patterns('', (r'^$', 'mysite.views.homepage'), (r'^(\d{4})/([a-z]{3})/$', 'mysite.views.archive_month'), ) if settings.DEBUG: urlpatterns += patterns('', (r'^debuginfo$', 'mysite.views.debug'), )
In this example, the URL /debuginfo/ will only be available if your DEBUG setting is set to True .
鍦ㄨ繖涓緥瀛愪腑锛孶RL /debuginfo/ 灏嗗彧鏈夊湪浣犵殑 DEBUG 閰嶇疆椤硅涓 True 鏃舵墠鏈夋晥銆
In all of our URLconf examples so far, weve used simple, non-named regular expression groups that is, we put parentheses around parts of the URL we wanted to capture, and Django passes that captured text to the view function as a positional argument. In more advanced usage, its possible to use named regular expression groups to capture URL bits and pass them as keyword arguments to a view.
鍒扮洰鍓嶄负姝紝鍦ㄦ墍鏈 URLconf 渚嬪瓙涓紝鎴戜滑浣跨敤鐨勫緢绠鍗曪紝鍗 鏃犲懡鍚 姝e垯琛ㄨ揪寮忕粍锛屽湪鎴戜滑鎯宠鎹曡幏鐨刄RL閮ㄥ垎涓婂姞涓婂皬鎷彿锛孌jango 浼氬皢鎹曡幏鐨勬枃鏈綔涓轰綅缃弬鏁颁紶閫掔粰瑙嗗浘鍑芥暟銆傚湪鏇撮珮绾х殑鐢ㄦ硶涓紝杩樺彲浠ヤ娇鐢 鍛藉悕 姝e垯琛ㄨ揪寮忕粍鏉ユ崟鑾稶RL锛屽苟涓斿皢鍏朵綔涓 鍏抽敭瀛 鍙傛暟浼犵粰瑙嗗浘銆
Keyword Arguments vs. Positional Arguments
鍏抽敭瀛楀弬鏁 瀵规瘮 浣嶇疆鍙傛暟
A Python function can be called using keyword arguments or positional arguments and, in some cases, both at the same time. In a keyword argument call, you specify the names of the arguments along with the values youre passing. In a positional argument call, you simply pass the arguments without explicitly specifying which argument matches which value; the association is implicit in the arguments order.
涓涓 Python 鍑芥暟鍙互浣跨敤鍏抽敭瀛楀弬鏁版垨浣嶇疆鍙傛暟鏉ヨ皟鐢紝鍦ㄦ煇浜涙儏鍐典笅锛屽彲浠ュ悓鏃惰繘琛屼娇鐢ㄣ傚湪鍏抽敭瀛楀弬鏁拌皟鐢ㄤ腑锛屼綘瑕佹寚瀹氬弬鏁扮殑鍚嶅瓧鍜屼紶鍏ョ殑鍊笺傚湪浣嶇疆鍙傛暟璋冪敤涓紝浣犲彧闇浼犲叆鍙傛暟锛屼笉闇瑕佹槑纭寚鏄庡摢涓弬鏁颁笌鍝釜鍊煎搴旓紝瀹冧滑鐨勫搴斿叧绯婚殣鍚湪鍙傛暟鐨勯『搴忎腑銆
For example, consider this simple function:
fozlR6 <a href=”http://alwpeqonzzpd.com/“>alwpeqonzzpd</a>, [url=http://eoblepdgxmzt.com/]eoblepdgxmzt[/url], [link=http://azkrzziaumle.com/]azkrzziaumle[/link], http://gfkmondejkch.com/
def sell(item, price, quantity): print "Selling %s unit(s) of %s at %s" % (quantity, item, price)
To call it with positional arguments, you specify the arguments in the order in which theyre listed in the function definition:
涓轰簡浣跨敤浣嶇疆鍙傛暟鏉ヨ皟鐢ㄥ畠锛屼綘瑕佹寜鐓у湪鍑芥暟瀹氫箟涓殑椤哄簭鏉ユ寚瀹氬弬鏁般
sell('Socks', '$2.50', 6)
To call it with keyword arguments, you specify the names of the arguments along with the values. The following statements are equivalent:
涓轰簡浣跨敤鍏抽敭瀛楀弬鏁版潵璋冪敤瀹冿紝浣犺鎸囧畾鍙傛暟鍚嶅拰鍊笺備笅闈㈢殑璇彞鏄瓑浠风殑:
sell(item='Socks', price='$2.50', quantity=6) sell(item='Socks', quantity=6, price='$2.50') sell(price='$2.50', item='Socks', quantity=6) sell(price='$2.50', quantity=6, item='Socks') sell(quantity=6, item='Socks', price='$2.50') sell(quantity=6, price='$2.50', item='Socks')
Finally, you can mix keyword and positional arguments, as long as all positional arguments are listed before keyword arguments. The following statements are equivalent to the previous examples:
鏈鍚庯紝浣犲彲浠ユ贩鍚堝叧閿瓧鍜屼綅缃弬鏁帮紝鍙鎵鏈夌殑浣嶇疆鍙傛暟鍒楀湪鍏抽敭瀛楀弬鏁颁箣鍓嶃備笅闈㈢殑璇彞涓庡墠闈㈢殑渚嬪瓙鏄瓑浠:
sell('Socks', '$2.50', quantity=6) sell('Socks', price='$2.50', quantity=6) sell('Socks', quantity=6, price='$2.50')
In Python regular expressions, the syntax for named regular expression groups is (?P<name>pattern) , where name is the name of the group and pattern is some pattern to match.
鍦 Python 姝e垯琛ㄨ揪寮忎腑锛屽懡鍚嶇殑姝e垯琛ㄨ揪寮忕粍鐨勮娉曟槸 (?P<name>pattern) 锛岃繖閲 name 鏄粍鐨勫悕瀛楋紝鑰 pattern 鏄尮閰嶇殑鏌愪釜妯″紡銆
Heres an example URLconf that uses non-named groups:
涓嬮潰鏄竴涓娇鐢ㄦ棤鍚嶇粍鐨 URLconf 鐨勪緥瀛:
from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^articles/(\d{4})/$', views.year_archive), (r'^articles/(\d{4})/(\d{2})/$', views.month_archive), )
Heres the same URLconf, rewritten to use named groups:
ZNpmIL <a href=”http://qucosvxmznkl.com/“>qucosvxmznkl</a>, [url=http://yjdxzjajhrsz.com/]yjdxzjajhrsz[/url], [link=http://zreyikrpzidz.com/]zreyikrpzidz[/link], http://esdpsbeowseu.com/
from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^articles/(?P<year>\d{4})/$', views.year_archive), (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', views.month_archive), )
This accomplishes exactly the same thing as the previous example, with one subtle difference: the captured values are passed to view functions as keyword arguments rather than positional arguments.
杩欐浠g爜鍜屽墠闈㈢殑鍔熻兘瀹屽叏涓鏍凤紝鍙湁涓涓粏寰殑宸埆锛氭妸鎻愬彇鐨勫肩敤鍛藉悕鍙傛暟鐨勬柟寮 浼犻掔粰瑙嗗浘鍑芥暟锛岃屼笉鏄敤鎸夐『搴忕殑鍖垮悕鍙傛暟鐨勬柟寮忋
For example, with non-named groups, a request to /articles/2006/03/ would result in a function call equivalent to this:
1tKNw5 <a href=”http://sdstpbzgmmbn.com/“>sdstpbzgmmbn</a>, [url=http://cvnjgcutyrcm.com/]cvnjgcutyrcm[/url], [link=http://reeabkflkcju.com/]reeabkflkcju[/link], http://bsppctebirpy.com/
month_archive(request, '2006', '03')
With named groups, though, the same request would result in this function call:
鑰屽甫鍛藉悕缁勶紝鍚屾牱鐨勮姹傚氨鏄繖鏍风殑鍑芥暟璋冪敤锛
month_archive(request, year='2006', month='03')
In practice, using named groups makes your URLconfs slightly more explicit and less prone to argument-order bugs and you can reorder the arguments in your views function definitions. Following the preceding example, if we wanted to change the URLs to include the month before the year, and we were using non-named groups, wed have to remember to change the order of arguments in the month_archive view. If we were using named groups, changing the order of the captured parameters in the URL would have no effect on the view.
浣跨敤鍛藉悕缁勫彲浠ヨ浣犵殑URLconfs鏇村姞娓呮櫚锛屽噺灏戝弬鏁版搴忓彲鑳芥悶娣风殑娼滃湪BUG锛岃繕鍙互 璁╀綘鍦ㄥ嚱鏁板畾涔変腑瀵瑰弬鏁伴噸鏂版帓搴忋傛帴鐫涓婇潰杩欎釜渚嬪瓙锛屽鏋滄垜浠兂淇敼URL鎶婃湀浠芥斁鍒 骞翠唤鐨 鍓嶉潰 锛岃屼笉浣跨敤鍛藉悕缁勭殑璇濓紝鎴戜滑灏变笉寰椾笉鍘讳慨鏀硅鍥 month_archive 鐨勫弬鏁版搴忋傚鏋滄垜浠娇鐢ㄥ懡鍚嶇粍鐨勮瘽锛屼慨鏀筓RL閲屾彁鍙栧弬鏁扮殑娆″簭瀵硅鍥炬病鏈夊奖鍝嶃
Of course, the benefits of named groups come at the cost of brevity; some developers find the named-group syntax ugly and too verbose. Still, another advantage of named groups is readability, especially by those who arent intimately familiar with regular expressions or your particular Django application. Its easier to see whats happening, at a glance, in a URLconf that uses named groups.
褰撶劧锛屽懡鍚嶇粍鐨勪唬浠峰氨鏄け鍘讳簡绠娲佹э細涓浜涘紑鍙戣呰寰楀懡鍚嶇粍鐨勮娉曚笐闄嬪拰鏄惧緱鍐椾綑銆 鍛藉悕缁勭殑鍙︿竴涓ソ澶勫氨鏄彲璇绘у己锛岀壒鍒槸鐔熸倝姝e垯琛ㄨ揪寮忔垨鑷繁寮鍙戠殑Django 搴旂敤鐨勫紑鍙戣呫傜湅涓鐪糢RLconf閲岀殑杩欎簺鍛藉悕缁勫氨鐭ラ亾杩欐槸骞蹭粈涔堢敤鐨勪簡銆
A caveat with using named groups in a URLconf is that a single URLconf pattern cannot contain both named and non-named groups. If you do this, Django wont throw any errors, but youll probably find that your URLs arent matching as you expect. Specifically, heres the algorithm the URLconf parser follows, with respect to named groups vs. non-named groups in a regular expression:
BsL55I <a href=”http://tasqioamrqly.com/“>tasqioamrqly</a>, [url=http://sftafnnqcumd.com/]sftafnnqcumd[/url], [link=http://ozgzxececcmx.com/]ozgzxececcmx[/link], http://uyetccdkpzdx.com/
If there are any named arguments, it will use those, ignoring non-named arguments.
濡傛灉鏈変换浣曞懡鍚嶇殑缁勶紝Django浼氬拷鐣ラ潪鍛藉悕缁勮岀洿鎺ヤ娇鐢ㄥ懡鍚嶇粍銆
Otherwise, it will pass all non-named arguments as positional arguments.
鍚﹀垯锛孌jango浼氭妸鎵鏈夐潪鍛藉悕缁勪互浣嶇疆鍙傛暟鐨勫舰寮忎紶閫掋
In both cases, it will pass any extra options as keyword arguments. See the next section for more information.
4CzvPf <a href=”http://bejuaosszhqg.com/“>bejuaosszhqg</a>, [url=http://mustddehuwps.com/]mustddehuwps[/url], [link=http://ogxgzaaxzdxl.com/]ogxgzaaxzdxl[/link], http://freqjzbnxehd.com/
3eZTaA <a href=”http://nmizqdrskmhq.com/“>nmizqdrskmhq</a>, [url=http://nsvgonwjlhyi.com/]nsvgonwjlhyi[/url], [link=http://osnzcwpdayxd.com/]osnzcwpdayxd[/link], http://posghywqmixc.com/
Sometimes youll find yourself writing view functions that are quite similar, with only a few small differences. For example, say you have two views whose contents are identical except for the template they use:
鏈夋椂浣犱細鍙戠幇浣犲啓鐨勮鍥惧嚱鏁版槸鍗佸垎绫讳技鐨勶紝鍙湁涓鐐圭偣鐨勪笉鍚屻傛瘮濡傝锛屼綘鏈変袱涓鍥撅紝瀹冧滑鐨勫唴瀹规槸涓鑷寸殑锛岄櫎浜嗗畠浠墍鐢ㄧ殑妯℃澘涓嶅お涓鏍凤細
# urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^foo/$', views.foo_view), (r'^bar/$', views.bar_view), ) # views.py from django.shortcuts import render_to_response from mysite.models import MyModel def foo_view(request): m_list = MyModel.objects.filter(is_new=True) return render_to_response('template1.html', {'m_list': m_list}) def bar_view(request): m_list = MyModel.objects.filter(is_new=True) return render_to_response('template2.html', {'m_list': m_list})
Were repeating ourselves in this code, and thats inelegant. At first, you may think to remove the redundancy by using the same view for both URLs, putting parentheses around the URL to capture it, and checking the URL within the view to determine the template, like so:
鎴戜滑鍦ㄨ繖浠g爜閲岄潰鍋氫簡閲嶅鐨勫伐浣滐紝涓嶅绠缁冦傝捣鍒濅綘鍙兘浼氭兂锛岄氳繃瀵逛袱涓猆RL閮借瘯鐢ㄥ悓鏍风殑瑙嗗浘锛屽湪URL涓娇鐢ㄦ嫭鍙锋崟鎹夎姹傦紝鐒跺悗鍦ㄨ鍥句腑妫鏌ュ苟鍐冲畾浣跨敤鍝釜妯℃澘鏉ュ幓闄や唬鐮佺殑鍐椾綑锛屽氨鍍忚繖鏍凤細
# urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^(foo)/$', views.foobar_view), (r'^(bar)/$', views.foobar_view), ) # views.py from django.shortcuts import render_to_response from mysite.models import MyModel def foobar_view(request, url): m_list = MyModel.objects.filter(is_new=True) if url == 'foo': template_name = 'template1.html' elif url == 'bar': template_name = 'template2.html' return render_to_response(template_name, {'m_list': m_list})
The problem with that solution, though, is that it couples your URLs to your code. If you decide to rename /foo/ to /fooey/ , youll have to remember to change the view code.
杩欑瑙e喅鏂规鐨勯棶棰樿繕鏄佺己鐐癸紝灏辨槸鎶婁綘鐨刄RL鑰﹀悎杩涗綘鐨勪唬鐮侀噷闈簡銆傚鏋滀綘鎵撶畻鎶 /foo/ 鏀规垚 /fooey/ 鐨勮瘽锛岄偅涔堜綘灏卞緱璁颁綇瑕佸幓鏀瑰彉瑙嗗浘閲岄潰鐨勪唬鐮併
The elegant solution involves an optional URLconf parameter. Each pattern in a URLconf may include a third item: a dictionary of keyword arguments to pass to the view function.
浼橀泤鐨勮В鍐虫柟娉曪細浣跨敤涓涓澶栫殑URLconf鍙傛暟銆備竴涓猆RLconf閲岄潰鐨勬瘡涓涓ā寮忓彲浠ュ寘鍚涓変釜鏁版嵁锛氫竴涓紶鍒拌鍥惧嚱鏁颁腑鐨勫叧閿瓧鍙傛暟鐨勫瓧鍏搞
With this in mind, we can rewrite our ongoing example like this:
鏈変簡杩欎釜姒傚康浠ュ悗锛屾垜浠氨鍙互鎶婃垜浠幇鍦ㄧ殑渚嬪瓙鏀瑰啓鎴愯繖鏍凤細
# urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^foo/$', views.foobar_view, {'template_name': 'template1.html'}), (r'^bar/$', views.foobar_view, {'template_name': 'template2.html'}), ) # views.py from django.shortcuts import render_to_response from mysite.models import MyModel def foobar_view(request, template_name): m_list = MyModel.objects.filter(is_new=True) return render_to_response(template_name, {'m_list': m_list})
As you can see, the URLconf in this example specifies template_name in the URLconf. The view function treats it as just another parameter.
濡備綘鎵瑙侊紝杩欎釜渚嬪瓙涓紝URLconf鎸囧畾浜 template_name 銆傝岃鍥惧嚱鏁板垯浼氭妸瀹冨鐞嗘垚鍙︿竴涓弬鏁拌屽凡銆
This extra URLconf options technique is a nice way of sending additional information to your view functions with minimal fuss. As such, its used by a couple of Djangos bundled applications, most notably its generic views system, which we cover in Chapter 9.
杩欓澶栫殑URLconf鍙傛暟鐨勬妧鏈互鏈灏戠殑楹荤儲缁欎綘鎻愪緵浜嗗悜瑙嗗浘鍑芥暟浼犻掗澶栦俊鎭殑涓涓ソ鏂规硶銆傛鍥犲姝わ紝杩欐妧鏈凡琚緢澶欴jango鐨勬崋缁戝簲鐢ㄤ娇鐢紝鍏朵腑浠ユ垜浠皢浼氬湪绗9绔犺璁虹殑閫氱敤瑙嗗浘绯荤粺鏈涓烘槑鏄俱
The following sections contain a couple of ideas on how you can use the extra URLconf options technique in your own projects.
涓嬮潰鐨勫嚑鑺傞噷闈㈡湁涓浜涘叧浜庝綘鍙互鎬庢牱鎶婇澶朥RLconf鍙傛暟鎶鏈簲鐢ㄥ埌浣犺嚜宸辩殑宸ョ▼鐨勫缓璁
Say you have a set of views that match a pattern, along with another URL that doesnt fit the pattern but whose view logic is the same. In this case, you can fake the capturing of URL values by using extra URLconf options to handle that extra URL with the same view.
姣斿璇翠綘鏈夊尮閰嶆煇涓ā寮忕殑涓鍫嗚鍥撅紝浠ュ強涓涓苟涓嶅尮閰嶈繖涓ā寮忕殑浣嗗畠鐨勮鍥鹃昏緫鏄竴鏍风殑URL銆傝繖绉嶆儏鍐典笅锛屼綘鍙互浼燯RL鍊肩殑鎹曟崏銆傝繖涓昏閫氳繃浣跨敤棰濆URLconf鍙傛暟锛屼娇寰楄繖涓鍑烘潵鐨刄RL浣跨敤鍚屼竴涓鍥俱
For example, you might have an application that displays some data for a particular day, with URLs such as these:
渚嬪锛屼綘鍙兘鏈変竴涓樉绀烘煇涓涓壒瀹氭棩瀛愮殑鏌愪簺鏁版嵁鐨勫簲鐢紝URL绫讳技杩欐牱鐨勶細
/mydata/jan/01/ /mydata/jan/02/ /mydata/jan/03/ # ... /mydata/dec/30/ /mydata/dec/31/
This is simple enough to deal with you can capture those in a URLconf like this (using named group syntax):
杩欏お绠鍗曚簡锛屼綘鍙互鍦ㄤ竴涓猆RLconf涓崟鎹夎繖浜涘硷紝鍍忚繖鏍凤紙浣跨敤鍛藉悕缁勭殑鏂规硶锛夛細
urlpatterns = patterns('', (r'^mydata/(?P<month>\w{3})/(?P<day>\d\d)/$', views.my_view), )
And the view function signature would look like this:
鐒跺悗瑙嗗浘鍑芥暟鐨勫師鍨嬬湅璧锋潵浼氭槸锛
def my_view(request, month, day): # ....
This approach is straightforward its nothing you havent seen before. The trick comes in when you want to add another URL that uses my_view but whose URL doesnt include a month and/or day .
杩欑瑙e喅鏂规寰堢洿鎺ワ紝娌℃湁鐢ㄥ埌浠涔堜綘娌¤杩囩殑鎶鏈傞棶棰樺湪浜庡綋浣犳兂涓烘坊鍔犱竴涓娇鐢 my_view 瑙嗗浘鐨刄RL浣嗗畠娌℃湁鍖呭惈涓涓 month 鍜/鎴栬 涓涓 day 銆
For example, you might want to add another URL, /mydata/birthday/ , which would be equivalent to /mydata/jan/06/ . You can take advantage of extra URLconf options like so:
姣斿浣犲彲鑳戒細鎯冲鍔犺繖鏍蜂竴涓猆RL锛 /mydata/birthday/ 锛 杩欎釜URL绛変环浜 /mydata/jan/06/ 銆傝繖鏃朵綘鍙互杩欐牱鍒╃敤棰濆URLconf鍙傛暟锛
urlpatterns = patterns('', (r'^mydata/birthday/$', views.my_view, {'month': 'jan', 'day': '06'}), (r'^mydata/(?P<month>\w{3})/(?P<day>\d\d)/$', views.my_view), )
The cool thing here is that you dont have to change your view function at all. The view function only cares that it gets month and day parameters it doesnt matter whether they come from the URL capturing itself or extra parameters.
鍦ㄨ繖閲屾渶甯呯殑鍦版柟鑾繃浜庝綘鏍规湰涓嶇敤鏀瑰彉浣犵殑瑙嗗浘鍑芥暟銆傝鍥惧嚱鏁板彧浼氬叧蹇冨畠 鑾峰緱 浜 month 鍜 day 鍙傛暟锛屽畠涓嶄細鍘荤杩欎簺鍙傛暟鍒板簳鏄崟鎹夊洖鏉ョ殑杩樻槸琚澶栨彁渚涚殑銆
Its good programming practice to factor out commonalities in code. For example, with these two Python functions:
鎶藉彇鍑烘垜浠唬鐮佷腑鍏辨х殑涓滆タ鏄竴涓緢濂界殑缂栫▼涔犳儻銆傛瘮濡傦紝鍍忎互涓嬬殑涓や釜Python鍑芥暟锛
def say_hello(person_name): print 'Hello, %s' % person_name def say_goodbye(person_name): print 'Goodbye, %s' % person_name
we can factor out the greeting to make it a parameter:
鎴戜滑鍙互鎶婇棶鍊欒鎻愬彇鍑烘潵鍙樻垚涓涓弬鏁帮細
def greet(person_name, greeting): print '%s, %s' % (greeting, person_name)
You can apply this same philosophy to your Django views by using extra URLconf parameters.
閫氳繃浣跨敤棰濆鐨刄RLconf鍙傛暟锛屼綘鍙互鎶婂悓鏍风殑鎬濇兂搴旂敤鍒癉jango鐨勮鍥句腑銆
With this in mind, you can start making higher-level abstractions of your views. Instead of thinking to yourself, This view displays a list of Event objects, and That view displays a list of BlogEntry objects, realize theyre both specific cases of A view that displays a list of objects, where the type of object is variable.
浜嗚В杩欎釜浠ュ悗锛屼綘鍙互寮濮嬪垱浣滈珮鎶借薄鐨勮鍥俱傛洿鍏蜂綋鍦拌锛屾瘮濡傝繖涓鍥炬樉绀轰竴绯诲垪鐨 Event 瀵硅薄锛岄偅涓鍥炬樉绀轰竴绯诲垪鐨 BlogEntry 瀵硅薄锛屽苟鎰忚瘑鍒板畠浠兘鏄竴涓敤鏉ユ樉绀轰竴绯诲垪瀵硅薄鐨勮鍥剧殑鐗逛緥锛岃屽璞$殑绫诲瀷鍏跺疄灏辨槸涓涓彉閲忋
Take this code, for example:
浠ヨ繖娈典唬鐮佷綔涓轰緥瀛愶細
# urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^events/$', views.event_list), (r'^blog/entries/$', views.entry_list), ) # views.py from django.shortcuts import render_to_response from mysite.models import Event, BlogEntry def event_list(request): obj_list = Event.objects.all() return render_to_response('mysite/event_list.html', {'event_list': obj_list}) def entry_list(request): obj_list = BlogEntry.objects.all() return render_to_response('mysite/blogentry_list.html', {'entry_list': obj_list})
The two views do essentially the same thing: they display a list of objects. So lets factor out the type of object theyre displaying:
杩欎袱涓鍥惧仛鐨勪簨鎯呭疄璐ㄤ笂鏄竴鏍风殑锛氭樉绀轰竴绯诲垪鐨勫璞°傝鎴戜滑鎶婂畠浠樉绀虹殑瀵硅薄鐨勭被鍨嬫娊璞″嚭鏉ワ細
# urls.py from django.conf.urls.defaults import * from mysite import models, views urlpatterns = patterns('', (r'^events/$', views.object_list, {'model': models.Event}), (r'^blog/entries/$', views.object_list, {'model': models.BlogEntry}), ) # views.py from django.shortcuts import render_to_response def object_list(request, model): obj_list = model.objects.all() template_name = 'mysite/%s_list.html' % model.__name__.lower() return render_to_response(template_name, {'object_list': obj_list})
With those small changes, we suddenly have a reusable, model-agnostic view! From now on, anytime we need a view that lists a set of objects, we can simply reuse this object_list view rather than writing view code. Here are a couple of notes about what we did:
灏辫繖鏍峰皬灏忕殑鏀瑰姩锛屾垜浠獊鐒跺彂鐜版垜浠湁浜嗕竴涓彲澶嶇敤鐨勶紝妯″瀷鏃犲叧鐨勮鍥撅紒浠庣幇鍦ㄥ紑濮嬶紝褰撴垜浠渶瑕佷竴涓鍥炬潵鏄剧ず涓绯诲垪鐨勫璞℃椂锛屾垜浠彲浠ョ畝绠鍗曞崟鐨勯噸鐢ㄨ繖涓涓 object_list 瑙嗗浘锛岃屾棤椤诲彟澶栧啓瑙嗗浘浠g爜浜嗐備互涓嬫槸鎴戜滑鍋氳繃鐨勪簨鎯咃細
Were passing the model classes directly, as the model parameter. The dictionary of extra URLconf options can pass any type of Python object not just strings.
鎴戜滑閫氳繃 model 鍙傛暟鐩存帴浼犻掍簡妯″瀷绫汇傞澶朥RLconf鍙傛暟鐨勫瓧鍏告槸鍙互浼犻掍换浣曠被鍨嬬殑瀵硅薄锛岃屼笉浠呬粎鍙槸瀛楃涓层
The model.objects.all() line is an example of duck typing : If it walks like a duck and talks like a duck, we can treat it like a duck. Note the code doesnt know what type of object model is; the only requirement is that model have an objects attribute, which in turn has an all() method.
杩欎竴琛岋細 model.objects.all() 鏄 楦瓙鐣屽畾 锛堝師鏂囷細duck typing锛屾槸璁$畻鏈虹瀛︿腑涓绉嶅姩鎬佺被鍨嬪垽鏂殑姒傚康锛夌殑涓涓緥瀛愶細濡傛灉涓鍙笩璧拌捣鏉ュ儚楦瓙锛屽彨璧锋潵鍍忛腑瀛愶紝閭f垜浠氨鍙互鎶婂畠褰撲綔鏄腑瀛愪簡銆傞渶瑕佹敞鎰忕殑鏄唬鐮佸苟涓嶇煡閬 model 瀵硅薄鐨勭被鍨嬫槸浠涔堬紱瀹冨彧瑕佹眰 model 鏈変竴涓 objects 灞炴э紝鑰岃繖涓睘鎬ф湁涓涓 all() 鏂规硶銆
Were using model.__name__.lower() in determining the template name. Every Python class has a __name__ attribute that returns the class name. This feature is useful at times like this, when we dont know the type of class until runtime. For example, the BlogEntry classs __name__ is the string 'BlogEntry' .
鎴戜滑浣跨敤 model.__name__.lower() 鏉ュ喅瀹氭ā鏉跨殑鍚嶅瓧銆傛瘡涓狿ython鐨勭被閮芥湁涓涓 __name__ 灞炴ц繑鍥炵被鍚嶃傝繖鐗规у湪褰撴垜浠洿鍒拌繍琛屾椂鍒绘墠鐭ラ亾瀵硅薄绫诲瀷鐨勮繖绉嶆儏鍐典笅寰堟湁鐢ㄣ傛瘮濡傦紝 BlogEntry 绫荤殑 __name__ 灏辨槸瀛楃涓 'BlogEntry' 銆
In a slight difference between this example and the previous example, were passing the generic variable name object_list to the template. We could easily change this variable name to be blogentry_list or event_list , but weve left that as an exercise for the reader.
杩欎釜渚嬪瓙涓庡墠闈㈢殑渚嬪瓙绋嶆湁涓嶅悓锛屾垜浠紶閫掍簡涓涓氱敤鐨勫彉閲忓悕缁欐ā鏉裤傚綋鐒舵垜浠彲浠ヨ交鏄撶殑鎶婅繖涓彉閲忓悕鏀规垚 blogentry_list 鎴栬 event_list 锛屼笉杩囨垜浠墦绠楁妸杩欏綋浣滅粌涔犵暀缁欒鑰呫
Because database-driven Web sites have several common patterns, Django comes with a set of generic views that use this exact technique to save you time. We cover Djangos built-in generic views in the next chapter.
鍥犱负鏁版嵁搴撻┍鍔ㄧ殑缃戠珯閮芥湁涓浜涢氱敤鐨勬ā寮忥紝Django鎻愪緵浜嗕竴涓氱敤瑙嗗浘鐨勯泦鍚堬紝浣跨敤瀹冨彲浠ヨ妭鐪佷綘鐨勬椂闂淬傛垜浠皢浼氬湪涓嬩竴绔犺璁睤jango鐨勫唴缃氱敤瑙嗗浘銆
If youre distributing a Django application, chances are that your users will want some degree of configuration. In this case, its a good idea to add hooks to your views for any configuration options you think people may want to change. You can use extra URLconf parameters for this purpose.
濡傛灉浣犲彂甯冧竴涓狣jango鐨勫簲鐢紝浣犵殑鐢ㄦ埛鍙兘浼氬笇鏈涢厤缃笂鑳芥湁浜涜嚜鐢卞害銆傝繖绉嶆儏鍐典笅锛屼负浣犺涓虹敤鎴峰彲鑳藉笇鏈涙敼鍙樼殑閰嶇疆閫夐」娣诲姞涓浜涢挬瀛愬埌浣犵殑瑙嗗浘涓細鏄竴涓緢濂界殑涓绘剰銆備綘鍙互鐢ㄩ澶朥RLconf鍙傛暟瀹炵幇銆
A common bit of an application to make configurable is the template name:
涓涓簲鐢ㄤ腑姣旇緝甯歌鐨勫彲渚涢厤缃唬鐮佹槸妯℃澘鍚嶅瓧锛
def my_view(request, template_name): var = do_something() return render_to_response(template_name, {'var': var})
When theres a conflict, extra URLconf parameters get precedence over captured parameters. In other words, if your URLconf captures a named-group variable and an extra URLconf parameter includes a variable with the same name, the extra URLconf parameter value will be used.
褰撳啿绐佸嚭鐜扮殑鏃跺欙紝棰濆URLconf鍙傛暟浼樺厛浜庢崟鎹夊笺備篃灏辨槸璇达紝濡傛灉URLconf鎹曟崏鍒扮殑涓涓懡鍚嶇粍鍙橀噺鍜屼竴涓澶朥RLconf鍙傛暟鍖呭惈鐨勫彉閲忓悓鍚嶆椂锛岄澶朥RLconf鍙傛暟鐨勫间細琚娇鐢ㄣ
For example, consider this URLconf:
渚嬪锛屼笅闈㈣繖涓猆RLconf锛
from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^mydata/(?P<id>\d+)/$', views.my_view, {'id': 3}), )
Here, both the regular expression and the extra dictionary include an id . The hard-coded id gets precedence. That means any request (e.g., /mydata/2/ or /mydata/432432/ ) will be treated as if id is set to 3 , regardless of the value captured in the URL.
杩欓噷锛屾鍒欒〃杈惧紡鍜岄澶栧瓧鍏搁兘鍖呭惈浜嗕竴涓 id 銆傜‖缂栫爜鐨勶紙棰濆瀛楀吀鐨勶級 id 灏嗕紭鍏堜娇鐢ㄣ傚氨鏄浠讳綍璇锋眰锛堟瘮濡傦紝 /mydata/2/ 鎴栬 /mydata/432432/ 锛夐兘浼氫綔 id 璁剧疆涓 3 瀵瑰緟锛屼笉绠RL閲岄潰鑳芥崟鎹夊埌浠涔堟牱鐨勫笺
Astute readers will note that in this case, its a waste of time and typing to capture the id in the regular expression, because its value will always be overridden by the dictionarys value. Thats correct; we bring this up only to help you avoid making the mistake.
鑱槑鐨勮鑰呬細鍙戠幇鍦ㄨ繖绉嶆儏鍐典笅锛屽湪姝e垯琛ㄨ揪寮忛噷闈㈠啓涓婃崟鎹夋槸娴垂鏃堕棿鐨勶紝鍥犱负 id 鐨勫兼绘槸浼氳瀛楀吀涓殑鍊艰鐩栥傛病閿欙紝鎴戜滑璇磋繖涓殑鐩殑鍙槸涓轰簡璁╀綘涓嶈鐘繖鏍风殑閿欒銆
Another convenient trick is to specify default parameters for a views arguments. This tells the view which value to use for a parameter by default if none is specified.
鍙﹀涓涓柟渚跨殑鐗规ф槸浣犲彲浠ョ粰涓涓鍥炬寚瀹氶粯璁ょ殑鍙傛暟銆傝繖鏍凤紝褰撴病鏈夌粰杩欎釜鍙傛暟璧嬪肩殑鏃跺欏皢浼氫娇鐢ㄩ粯璁ょ殑鍊笺
Heres an example:
璇风湅渚嬪瓙锛
# urls.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^blog/$', views.page), (r'^blog/page(?P<num>\d+)/$', views.page), ) # views.py def page(request, num="1"): # Output the appropriate page of blog entries, according to num. # ...
Here, both URL patterns point to the same view views.page but the first pattern doesnt capture anything from the URL. If the first pattern matches, the page() function will use its default argument for num , "1" . If the second pattern matches, page() will use whatever num value was captured by the regular expression.
鍦ㄨ繖閲岋紝涓や釜URL琛ㄨ揪寮忛兘鎸囧悜浜嗗悓涓涓鍥 views.page 锛屼絾鏄涓涓〃杈惧紡娌℃湁浼犻掍换浣曞弬鏁般傚鏋滃尮閰嶅埌浜嗙涓涓牱寮忥紝 page() 鍑芥暟灏嗕細瀵瑰弬鏁 num 浣跨敤榛樿鍊 "1" 锛屽鏋滅浜屼釜琛ㄨ揪寮忓尮閰嶆垚鍔燂紝 page() 鍑芥暟灏嗕娇鐢ㄦ鍒欒〃杈惧紡浼犻掕繃鏉ョ殑num鐨勫笺
Its common to use this technique in conjunction with configuration options, as explained earlier. This example makes a slight improvement to the example in the Giving a View Configuration Options section by providing a default value for template_name :
灏卞儚鍓嶉潰瑙i噴鐨勪竴鏍凤紝杩欑鎶鏈笌閰嶇疆閫夐」鐨勮仈鐢ㄦ槸寰堟櫘閬嶇殑銆備互涓嬭繖涓緥瀛愭瘮鎻愪緵瑙嗗浘閰嶇疆閫夐」涓鑺備腑鐨勪緥瀛愭湁浜涜鐨勬敼杩涖傚畠涓 template_name 鎻愪緵浜嗕竴涓粯璁ゅ硷細
def my_view(request, template_name='mysite/my_view.html'): var = do_something() return render_to_response(template_name, {'var': var})
Sometimes youll have a pattern in your URLconf that handles a large set of URLs, but youll need to special-case one of them. In this case, take advantage of the linear way a URLconf is processed and put the special case first.
鏈夋椂浣犳湁涓涓ā寮忔潵澶勭悊鍦ㄤ綘鐨刄RLconf涓殑涓绯诲垪URL锛屼絾鏄湁鏃跺欓渶瑕佺壒鍒鐞嗗叾涓殑鏌愪釜URL銆傚湪杩欑鎯呭喌涓嬶紝瑕佷娇鐢ㄥ皢URLconf涓妸鐗规畩鎯呭喌鏀惧湪棣栦綅鐨勭嚎鎬у鐞嗘柟寮 銆
For example, the add an object pages in Djangos admin site are represented by this URLconf line:
渚嬪锛孌jango鐨刟dmin绔欑偣涓坊鍔犱竴涓璞¢〉闈㈡槸濡備笅閰嶇疆鐨勶細
urlpatterns = patterns('', # ... ('^([^/]+)/([^/]+)/add/$', 'django.contrib.admin.views.main.add_stage'), # ... )
This matches URLs such as /myblog/entries/add/ and /auth/groups/add/ . However, the add page for a user object (/auth/user/add/ ) is a special case it doesnt display all of the form fields, it displays two password fields, and so forth. We could solve this problem by special-casing in the view, like so:
杩欏皢鍖归厤鍍 /myblog/entries/add/ 鍜 /auth/groups/add/ 杩欐牱鐨刄RL 銆傜劧鑰岋紝瀵逛簬鐢ㄦ埛瀵硅薄鐨勬坊鍔犻〉闈紙 /auth/user/add/ 锛夋槸涓壒娈婃儏鍐碉紝鍥犱负瀹冧笉浼氭樉绀烘墍鏈夌殑琛ㄥ崟鍩燂紝瀹冩樉绀轰袱涓瘑鐮佸煙绛夌瓑銆傛垜浠 鍙互 鍦ㄨ鍥句腑鐗瑰埆鎸囧嚭浠ヨВ鍐宠繖绉嶆儏鍐碉細
def add_stage(request, app_label, model_name): if app_label == 'auth' and model_name == 'user': # do special-case code else: # do normal code
but thats inelegant for a reason weve touched on multiple times in this chapter: it puts URL logic in the view. As a more elegant solution, we can take advantage of the fact that URLconfs are processed in order from top to bottom:
涓嶈繃锛屽氨濡傛垜浠娆″湪杩欑珷鎻愬埌鐨勶紝杩欐牱鍋氬苟涓嶄紭闆咃細鍥犱负瀹冩妸URL閫昏緫鏀惧湪浜嗚鍥句腑銆傛洿浼橀泤鐨勮В鍐虫柟娉曟槸锛屾垜浠鍒╃敤URLconf浠庨《鍚戜笅鐨勮В鏋愰『搴忚繖涓壒鐐癸細
urlpatterns = patterns('', # ... ('^auth/user/add/$', 'django.contrib.admin.views.auth.user_add_stage'), ('^([^/]+)/([^/]+)/add/$', 'django.contrib.admin.views.main.add_stage'), # ... )
With this in place, a request to /auth/user/add/ will be handled by the user_add_stage view. Although that URL matches the second pattern, it matches the top one first. (This is short-circuit logic.)
鍦ㄨ繖绉嶆儏鍐典笅锛岃薄 /auth/user/add/ 鐨勮姹傚皢浼氳 user_add_stage 瑙嗗浘澶勭悊銆傚敖绠RL涔熷尮閰嶇浜岀妯″紡锛屽畠浼氬厛鍖归厤涓婇潰鐨勬ā寮忋傦紙杩欐槸鐭矾閫昏緫銆傦級
Each captured argument is sent to the view as a plain Python string, regardless of what sort of match the regular expression makes. For example, in this URLconf line:
姣忎釜琚崟鑾风殑鍙傛暟灏嗚浣滀负绾疨ython瀛楃涓叉潵鍙戦侊紝鑰屼笉绠℃鍒欒〃杈惧紡涓殑鏍煎紡銆備妇涓緥瀛愶紝鍦ㄨ繖琛孶RLConf涓細
(r'^articles/(?P<year>\d{4})/$', views.year_archive),
the year argument to views.year_archive() will be a string, not an integer, even though \d{4} will only match integer strings.
灏界 \d{4} 灏嗗彧鍖归厤鏁存暟鐨勫瓧绗︿覆锛屼絾鏄弬鏁 year 鏄綔涓哄瓧绗︿覆浼犺嚦 views.year_archive() 鐨勶紝鑰屼笉鏄暣鍨嬨
This is important to keep in mind when youre writing view code. Many built-in Python functions are fussy (and rightfully so) about accepting only objects of a certain type. A common error is to attempt to create a datetime.date object with string values instead of integer values:
褰撲綘鍦ㄥ啓瑙嗗浘浠g爜鏃惰浣忚繖鐐瑰緢閲嶈锛岃澶歅ython鍐呭缓鐨勬柟娉曞浜庢帴鍙楃殑瀵硅薄鐨勭被鍨嬪緢璁茬┒銆備竴涓吀鍨嬬殑鐨勯敊璇氨鏄敤瀛楃涓插艰屼笉鏄暣鏁板兼潵鍒涘缓 datetime.date 瀵硅薄锛
>>> import datetime >>> datetime.date('1993', '7', '9') Traceback (most recent call last): ... TypeError: an integer is required >>> datetime.date(1993, 7, 9) datetime.date(1993, 7, 9)
Translated to a URLconf and view, the error looks like this:
鍥炲埌URLconf鍜岃鍥惧锛岄敊璇湅璧锋潵寰堝彲鑳芥槸杩欐牱锛
# urls.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^articles/(\d{4})/(\d{2})/(\d{2})/$', views.day_archive), ) # views.py import datetime def day_archive(request, year, month, day) # The following statement raises a TypeError! date = datetime.date(year, month, day)
Instead, day_archive() can be written correctly like this:
鍥犳锛 day_archive() 搴旇杩欐牱鍐欐墠鏄纭殑锛
def day_archive(request, year, month, day) date = datetime.date(int(year), int(month), int(day))
Note that int() itself raises a ValueError when you pass it a string that is not composed solely of digits, but were avoiding that error in this case because the regular expression in our URLconf has ensured that only strings containing digits are passed to the view function.
娉ㄦ剰锛屽綋浣犱紶閫掍簡涓涓苟涓嶅畬鍏ㄥ寘鍚暟瀛楃殑瀛楃涓叉椂锛 int() 浼氭姏鍑 ValueError 鐨勫紓甯革紝涓嶈繃鎴戜滑宸茬粡閬垮厤浜嗚繖涓敊璇紝鍥犱负鍦║RLconf鐨勬鍒欒〃杈惧紡涓凡缁忕‘淇濆彧鏈夊寘鍚暟瀛楃殑瀛楃涓叉墠浼氫紶鍒拌繖涓鍥惧嚱鏁颁腑銆
When a request comes in, Django tries to match the URLconf patterns against the requested URL, as a normal Python string (not as a Unicode string). This does not include GET or POST parameters, or the domain name. It also does not include the leading slash, because every URL has a leading slash.
褰撲竴涓姹傝繘鏉ユ椂锛孌jango璇曠潃灏嗚姹傜殑URL浣滀负涓涓櫘閫歅ython瀛楃涓茶繘琛孶RLconf妯″紡鍖归厤锛堣屼笉鏄綔涓轰竴涓猆nicode瀛楃涓诧級銆傝繖骞朵笉鍖呮嫭 GET 鎴 POST 鍙傛暟鎴栧煙鍚嶃傚畠涔熶笉鍖呮嫭绗竴涓枩鏉狅紝鍥犱负姣忎釜URL蹇呭畾鏈変竴涓枩鏉犮
For example, in a request to http://www.example.com/myapp/ , Django will try to match myapp/ . In a request to http://www.example.com/myapp/?page=3 , Django will try to match myapp/ .
渚嬪锛屽湪鍚 http://www.example.com/myapp/ 鐨勮姹備腑锛孌jango灏嗚瘯鐫鍘诲尮閰 myapp/ 銆傚湪鍚 http://www.example.com/myapp/?page=3 鐨勮姹備腑锛孌jango鍚屾牱浼氬幓鍖归厤 myapp/ 銆
The request method (e.g., POST , GET , HEAD ) is not taken into account when traversing the URLconf. In other words, all request methods will be routed to the same function for the same URL. Its the responsibility of a view function to perform branching based on request method.
鍦ㄨВ鏋怳RLconf鏃讹紝璇锋眰鏂规硶锛堜緥濡傦紝 POST 锛 GET 锛 HEAD 锛夊苟 涓嶄細 琚冭檻銆傛崲鑰岃█涔嬶紝瀵逛簬鐩稿悓鐨刄RL鐨勬墍鏈夎姹傛柟娉曞皢琚鍚戝埌鐩稿悓鐨勫嚱鏁颁腑銆傚洜姝ゆ牴鎹姹傛柟娉曟潵澶勭悊鍒嗘敮鏄鍥惧嚱鏁扮殑璐d换銆
If you intend your code to be used on multiple Django-based sites, you should consider arranging your URLconfs in such a way that allows for including.
濡傛灉浣犺瘯鍥捐浣犵殑浠g爜鐢ㄥ湪澶氫釜鍩轰簬Django鐨勭珯鐐逛笂锛屼綘搴旇鑰冭檻灏嗕綘鐨刄RLconf浠ュ寘鍚殑鏂瑰紡鏉ュ鐞嗐
At any point, your URLconf can include other URLconf modules. This essentially roots a set of URLs below other ones. For example, this URLconf includes other URLconfs:
鍦ㄤ换浣曟椂鍊欙紝浣犵殑URLconf閮藉彲浠ュ寘鍚叾浠朥RLconf妯″潡銆傚浜庢牴鐩綍鏄熀浜庝竴绯诲垪URL鐨勭珯鐐规潵璇达紝杩欐槸蹇呰鐨勩備緥濡備笅闈㈢殑锛孶RLconf鍖呭惈浜嗗叾浠朥RLConf锛
from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^weblog/', include('mysite.blog.urls')), (r'^photos/', include('mysite.photos.urls')), (r'^about/$', 'mysite.views.about'), )
Theres an important gotcha here: the regular expressions in this example that point to an include() do not have a $ (end-of-string match character) but do include a trailing slash. Whenever Django encounters include() , it chops off whatever part of the URL matched up to that point and sends the remaining string to the included URLconf for further processing.
杩欓噷鏈変釜寰堥噸瑕佺殑鍦版柟锛氫緥瀛愪腑鐨勬寚鍚 include() 鐨勬鍒欒〃杈惧紡骞 涓 鍖呭惈涓涓 $ 锛堝瓧绗︿覆缁撳熬鍖归厤绗︼級锛屼絾鏄寘鍚簡涓涓枩鏉嗐傛瘡褰揇jango閬囧埌 include() 鏃讹紝瀹冨皢鎴柇鍖归厤鐨刄RL锛屽苟鎶婂墿浣欑殑瀛楃涓插彂寰鍖呭惈鐨刄RLconf浣滆繘涓姝ュ鐞嗐
Continuing this example, heres the URLconf mysite.blog.urls :
缁х画鐪嬭繖涓緥瀛愶紝杩欓噷灏辨槸琚寘鍚殑URLconf mysite.blog.urls 锛
from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^(\d\d\d\d)/$', 'mysite.blog.views.year_detail'), (r'^(\d\d\d\d)/(\d\d)/$', 'mysite.blog.views.month_detail'), )
With these two URLconfs, heres how a few sample requests would be handled:
閫氳繃杩欎袱涓猆RLconf锛屼笅闈㈡槸涓浜涘鐞嗚姹傜殑渚嬪瓙锛
/weblog/2007/ : In the first URLconf, the pattern r'^weblog/' matches. Because it is an include() , Django strips all the matching text, which is 'weblog/' in this case. The remaining part of the URL is 2007/ , which matches the first line in the mysite.blog.urls URLconf.
/weblog/2007/ 锛氬湪绗竴涓猆RLconf涓紝妯″紡 r'^weblog/' 琚尮閰嶃傚洜涓哄畠鏄竴涓 include() 锛孌jango灏嗘埅鎺夋墍鏈夊尮閰嶇殑鏂囨湰锛屽湪杩欓噷鏄 'weblog/' 銆俇RL鍓╀綑鐨勯儴鍒嗘槸 2007/ 锛 灏嗗湪 mysite.blog.urls 杩欎釜URLconf鐨勭涓琛屼腑琚尮閰嶅埌銆
/weblog//2007/ : In the first URLconf, the pattern r'^weblog/' matches. Because it is an include() , Django strips all the matching text, which is 'weblog/' in this case. The remaining part of the URL is /2007/ (with a leading slash), which does not match any of the lines in the mysite.blog.urls URLconf.
/weblog//2007/ 锛氬湪绗竴涓猆RLconf涓紝妯″紡 r'^weblog/' 琚尮閰嶃傚洜涓哄畠鏄竴涓 include() 锛孌jango灏嗘埅鎺夋墍鏈夊尮閰嶇殑鏂囨湰锛屽湪杩欓噷鏄 'weblog/' 銆俇RL鍓╀綑鐨勯儴鍒嗘槸 /2007/ (寮澶存湁涓涓枩鏉)锛屽皢涓嶄細鍖归厤 mysite.blog.urls 涓殑浠讳綍URLconf銆
/about/ : This matches the view mysite.views.about in the first URLconf, demonstrating that you can mix include() patterns with non-include() patterns.
/about/ : 杩欎釜鍖归厤绗竴涓猆RLconf涓殑 mysite.views.about 瑙嗗浘銆傚彧鏄负浜嗙ず鑼冧綘鍙互娣峰悎 include() patterns鍜 non-include() patterns鍦ㄤ竴璧蜂娇鐢ㄣ
An included URLconf receives any captured parameters from parent URLconfs, for example:
涓涓鍖呭惈鐨刄RLconf鎺ユ敹浠讳綍鏉ヨ嚜parent URLconfs鐨勮鎹曡幏鐨勫弬鏁帮紝姣斿:
# root urls.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^(?P<username>\w+)/blog/', include('foo.urls.blog')), ) # foo/urls/blog.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^$', 'foo.views.blog_index'), (r'^archive/$', 'foo.views.blog_archive'), )
In this example, the captured username variable is passed to the included URLconf and, hence, to every view function within that URLconf.
鍦ㄨ繖涓緥瀛愪腑锛岃鎹曡幏鐨 username 鍙橀噺灏嗕紶閫掔粰琚寘鍚殑 URLconf锛岃繘鑰屼紶閫掔粰閭d釜URLconf涓殑 姣忎竴涓 瑙嗗浘鍑芥暟銆
Note that the captured parameters will always be passed to every line in the included URLconf, regardless of whether the lines view actually accepts those parameters as valid. For this reason, this technique is useful only if youre certain that every view in the included URLconf accepts the parameters youre passing.
娉ㄦ剰锛岃繖涓鎹曡幏鐨勫弬鏁 鎬绘槸 浼犻掑埌琚寘鍚殑URLconf涓殑 姣忎竴 琛岋紝涓嶇閭d簺琛屽搴旂殑瑙嗗浘鏄惁闇瑕佽繖浜涘弬鏁般傚洜姝わ紝杩欎釜鎶鏈彧鏈夊湪浣犵‘瀹為渶瑕侀偅涓浼犻掔殑鍙傛暟鐨勬椂鍊欐墠鏄惧緱鏈夌敤銆
Similarly, you can pass extra URLconf options to include() , just as you can pass extra URLconf options to a normal view as a dictionary. When you do this, each line in the included URLconf will be passed the extra options.
鐩镐技鐨勶紝浣犲彲浠ヤ紶閫掗澶栫殑URLconf閫夐」鍒 include() , 灏卞儚浣犲彲浠ラ氳繃瀛楀吀浼犻掗澶栫殑URLconf閫夐」鍒版櫘閫氱殑瑙嗗浘銆傚綋浣犺繖鏍峰仛鐨勬椂鍊欙紝琚寘鍚玌RLconf鐨 姣忎竴 琛岄兘浼氭敹鍒伴偅浜涢澶栫殑鍙傛暟銆
For example, the following two URLconf sets are functionally identical.
姣斿锛屼笅闈㈢殑涓や釜URLconf鍦ㄥ姛鑳戒笂鏄浉绛夌殑銆
Set one:
绗竴涓細
# urls.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^blog/', include('inner'), {'blogid': 3}), ) # inner.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^archive/$', 'mysite.views.archive'), (r'^about/$', 'mysite.views.about'), (r'^rss/$', 'mysite.views.rss'), )
Set two:
绗簩涓
# urls.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^blog/', include('inner')), ) # inner.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^archive/$', 'mysite.views.archive', {'blogid': 3}), (r'^about/$', 'mysite.views.about', {'blogid': 3}), (r'^rss/$', 'mysite.views.rss', {'blogid': 3}), )
As is the case with captured parameters (explained in the previous section), extra options will always be passed to every line in the included URLconf, regardless of whether the lines view actually accepts those options as valid. For this reason, this technique is useful only if youre certain that every view in the included URLconf accepts the extra options youre passing.
杩欎釜渚嬪瓙鍜屽墠闈㈠叧浜庤鎹曡幏鐨勫弬鏁颁竴鏍凤紙鍦ㄤ笂涓鑺傚氨瑙i噴杩囪繖涓鐐癸級锛岄澶栫殑閫夐」灏 鎬绘槸 琚紶閫掑埌琚寘鍚殑URLconf涓殑 姣忎竴 琛岋紝涓嶇閭d竴琛屽搴旂殑瑙嗗浘鏄惁纭疄浣滀负鏈夋晥鍙傛暟鎺ユ敹杩欎簺閫夐」锛屽洜姝わ紝杩欎釜鎶鏈彧鏈夊湪浣犵‘瀹為渶瑕侀偅涓浼犻掔殑棰濆鍙傛暟鐨勬椂鍊欐墠鏄惧緱鏈夌敤銆
One of Djangos main goals is to reduce the amount of code developers need to write, and in this chapter we suggested how to cut down the code of your views and URLconfs.
Django鐨勪富瑕佺洰鏍囦箣涓灏辨槸鍑忓皯寮鍙戣呯殑浠g爜杈撳叆閲忥紝骞朵笖鍦ㄨ繖涓绔犱腑鎴戜滑寤鸿濡備綍鍑忓皯浣犵殑瑙嗗浘鍜孶RLconf鐨勪唬鐮侀噺銆
The next logical step in code elimination is removing the need to write views entirely. Thats the topic of the next chapter.
涓轰簡鍑忓皯浠g爜閲忥紝涓嬩竴涓悎鐞嗘楠ゅ氨鏄浣曢伩鍏嶅叏閮ㄦ墜宸ヤ功鍐欒鍥句唬鐮侊紝杩欏氨鏄笅涓绔犵殑涓婚銆
鍏充簬鏈瘎娉ㄧ郴缁
鏈珯浣跨敤涓婁笅鏂囧叧鑱旂殑璇勬敞绯荤粺鏉ユ敹闆嗗弽棣堜俊鎭備笉鍚屼簬涓鑸鏁寸珷鍋氳瘎娉ㄧ殑鍋氭硶锛 鎴戜滑鍏佽浣犲姣忎竴涓嫭绔嬬殑鈥滄枃鏈潡鈥濆仛璇勬敞銆備竴涓滄枃鏈潡鈥濈湅璧锋潵鏄繖鏍风殑锛
涓涓滄枃鏈潡鈥濇槸涓涓钀斤紝涓涓垪琛ㄩ」锛屼竴娈典唬鐮侊紝鎴栬呭叾浠栦竴灏忔鍐呭銆 浣犻変腑瀹冧細楂樹寒搴︽樉绀:
瑕佸鏂囨湰鍧楀仛璇勬敞锛屼綘鍙渶瑕佺偣鍑诲畠鏃佽竟鐨勬爣璇嗗潡:
鎴戜滑浼氫粩缁嗛槄璇绘瘡涓瘎璁猴紝濡傛灉鍙兘鐨勮瘽鎴戜滑涔熶細鎶婅瘎娉ㄨ冭檻鍒版湭鏉ョ殑鐗堟湰涓幓:
濡傛灉浣犳効鎰忎綘鐨勮瘎娉ㄨ閲囩敤锛岃纭繚鐣欎笅浣犵殑鍏ㄥ悕 (娉ㄦ剰涓嶆槸鏄电О鎴栫畝绉帮級
Many, many thanks to Jack Slocum; the inspiration and much of the code for the comment system comes from Jack's blog, and this site couldn't have been built without his wonderful
YAHOO.ext
library. Thanks also to Yahoo for YUI itself.