The Django Book

Chapter 8: Advanced Views and URLconfs

绗叓绔 楂樼骇瑙嗗浘鍜孶RL閰嶇疆

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閰嶇疆锛岃繖涓绔犲皢娑夊強鏇村缁嗚妭鍜岄珮绾у姛鑳姐

URLconf Tricks

URLconf 鎶宸

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/

Streamlining Function Imports

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 涓贩鐢ㄥ畠浠傚喅瀹氭潈鍦ㄤ綘銆

Using Multiple View Prefixes

浣跨敤澶氫釜瑙嗗浘鍓嶇紑

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鏈緥涓垜浠墍鍋氱殑涓鏍枫

Special-Casing URLs in Debug Mode

璋冭瘯妯″紡涓殑鐗逛緥

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 鏃舵墠鏈夋晥銆

Using Named Groups

浣跨敤鍛藉悕缁

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閲岀殑杩欎簺鍛藉悕缁勫氨鐭ラ亾杩欐槸骞蹭粈涔堢敤鐨勪簡銆

Understanding the Matching/Grouping Algorithm

鐞嗚В鍖归厤/鍒嗙粍绠楁硶

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/

Passing Extra Options to View Functions

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鍙傛暟鎶鏈簲鐢ㄥ埌浣犺嚜宸辩殑宸ョ▼鐨勫缓璁

Faking Captured URLconf Values
浼犳崟鎹夊埌鐨刄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.

鍦ㄨ繖閲屾渶甯呯殑鍦版柟鑾繃浜庝綘鏍规湰涓嶇敤鏀瑰彉浣犵殑瑙嗗浘鍑芥暟銆傝鍥惧嚱鏁板彧浼氬叧蹇冨畠 鑾峰緱monthday 鍙傛暟锛屽畠涓嶄細鍘荤杩欎簺鍙傛暟鍒板簳鏄崟鎹夊洖鏉ョ殑杩樻槸琚澶栨彁渚涚殑銆

Making a View Generic
鍒涘缓涓涓氱敤瑙嗗浘

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鐨勫唴缃氱敤瑙嗗浘銆

Giving a View Configuration Options
鎻愪緵瑙嗗浘閰嶇疆閫夐」

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})
Understanding Precedence of Captured Values vs. Extra Options
浜嗚В鎹曟崏鍊煎拰棰濆鍙傛暟涔嬮棿鐨勪紭鍏堢骇

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 鐨勫兼绘槸浼氳瀛楀吀涓殑鍊艰鐩栥傛病閿欙紝鎴戜滑璇磋繖涓殑鐩殑鍙槸涓轰簡璁╀綘涓嶈鐘繖鏍风殑閿欒銆

Using Default View Arguments

浣跨敤缂虹渷瑙嗗浘鍙傛暟

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})

Special-Casing Views

鐗规畩鎯呭喌涓嬬殑瑙嗗浘

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涔熷尮閰嶇浜岀妯″紡锛屽畠浼氬厛鍖归厤涓婇潰鐨勬ā寮忋傦紙杩欐槸鐭矾閫昏緫銆傦級

Capturing Text in URLs

浠嶶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鐨勬鍒欒〃杈惧紡涓凡缁忕‘淇濆彧鏈夊寘鍚暟瀛楃殑瀛楃涓叉墠浼氫紶鍒拌繖涓鍥惧嚱鏁颁腑銆

Determining What the URLconf Searches Against

鍐冲畾URLconf鎼滅储鐨勪笢瑗

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瀛楃涓诧級銆傝繖骞朵笉鍖呮嫭 GETPOST 鍙傛暟鎴栧煙鍚嶃傚畠涔熶笉鍖呮嫭绗竴涓枩鏉狅紝鍥犱负姣忎釜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鏃讹紝璇锋眰鏂规硶锛堜緥濡傦紝 POSTGETHEAD 锛夊苟 涓嶄細 琚冭檻銆傛崲鑰岃█涔嬶紝瀵逛簬鐩稿悓鐨刄RL鐨勬墍鏈夎姹傛柟娉曞皢琚鍚戝埌鐩稿悓鐨勫嚱鏁颁腑銆傚洜姝ゆ牴鎹姹傛柟娉曟潵澶勭悊鍒嗘敮鏄鍥惧嚱鏁扮殑璐d换銆

Including Other URLconfs

鍖呭惈鍏朵粬URLconf

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鍦ㄤ竴璧蜂娇鐢ㄣ

How Captured Parameters Work with include()

鎹曡幏鐨勫弬鏁板浣曞拰include()鍗忓悓宸ヤ綔

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簺琛屽搴旂殑瑙嗗浘鏄惁闇瑕佽繖浜涘弬鏁般傚洜姝わ紝杩欎釜鎶鏈彧鏈夊湪浣犵‘瀹為渶瑕侀偅涓浼犻掔殑鍙傛暟鐨勬椂鍊欐墠鏄惧緱鏈夌敤銆

How Extra URLconf Options Work with include()

棰濆鐨刄RLconf濡備綍鍜宨nclude()鍗忓悓宸ヤ綔

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竴琛屽搴旂殑瑙嗗浘鏄惁纭疄浣滀负鏈夋晥鍙傛暟鎺ユ敹杩欎簺閫夐」锛屽洜姝わ紝杩欎釜鎶鏈彧鏈夊湪浣犵‘瀹為渶瑕侀偅涓浼犻掔殑棰濆鍙傛暟鐨勬椂鍊欐墠鏄惧緱鏈夌敤銆

Whats Next?

鎺ヤ笅鏉?

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爜閲忥紝涓嬩竴涓悎鐞嗘楠ゅ氨鏄浣曢伩鍏嶅叏閮ㄦ墜宸ヤ功鍐欒鍥句唬鐮侊紝杩欏氨鏄笅涓绔犵殑涓婚銆

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.