Guest author: Simon Willison
鏈珷浣滆呮槸Simon Willison
After following along with the last chapter, you should now have a fully functioning if somewhat simple site. In this chapter, well deal with the next piece of the puzzle: building views that take input from readers.
缁忚繃涓婁竴绔狅紝浣犲簲璇ュ绠鍗曠綉绔欐湁涓叏闈㈢殑璁よ瘑銆傝繖涓绔狅紝鏉ュ鐞唚eb寮鍙戠殑涓嬩竴涓毦棰橈細寤虹珛鐢ㄦ埛杈撳叆鐨勮鍥俱
Well start by making a simple search form by hand and looking at how to handle data submitted from the browser. From there, well move on to using Djangos forms framework.
鎴戜滑浼氫粠鎵嬪伐鎵撻犱竴涓畝鍗曠殑鎼滅储椤甸潰寮濮嬶紝鐪嬬湅鎬庢牱澶勭悊娴忚鍣ㄦ彁浜よ屾潵鐨勬暟鎹傜劧鍚庢垜浠紑濮嬩娇鐢―jango鐨刦orms妗嗘灦銆
The Web is all about search. Two of the Nets biggest success stories, Google and Yahoo, built their multi-billion-dollar businesses around search. Nearly every site sees a large percentage of traffic coming to and from its search pages. Often the difference between the success or failure of a site is the quality of its search. So it looks like wed better add some searching to our fledgling books site, no?
鍦╳eb搴旂敤涓婏紝鏈変袱涓叧浜庢悳绱㈣幏寰楀法澶ф垚鍔熺殑鏁呬簨锛欸oogle鍜孻ahoo锛岄氳繃鎼滅储锛屼粬浠缓绔嬩簡鍑犲崄浜跨編鍏冪殑涓氬姟銆傚嚑涔庢瘡涓綉绔欓兘鏈夊緢澶х殑姣斾緥璁块棶閲忔潵鑷繖涓や釜鎼滅储寮曟搸銆傜敋鑷筹紝涓涓綉绔欐槸鍚︽垚鍔熷彇鍐充簬鍏剁珯鍐呮悳绱㈢殑璐ㄩ噺銆傚洜姝わ紝鍦ㄦ垜浠繖涓綉绔欐坊鍔犳悳绱㈠姛鑳界湅璧锋潵濂戒竴浜涖
Well start by adding the search view to our URLconf (mysite.urls ). Recall that this means adding something like (r'^search/$', 'mysite.books.views.search') to the set of URL patterns.
寮濮嬶紝鍦║RLconf (mysite.urls )娣诲姞鎼滅储瑙嗗浘銆傛坊鍔犵被浼 (r'^search/$','mysite.books.views.search') 璁剧疆URL妯″紡銆
Next, well write this search view into our view module (mysite.books.views ):
涓嬩竴姝ワ紝鍦ㄨ鍥炬ā鍧(mysite.books.views )涓啓杩欎釜 search 瑙嗗浘:
from django.db.models import Q from django.shortcuts import render_to_response from models import Book def search(request): query = request.GET.get('q', '') if query: qset = ( Q(title__icontains=query) | Q(authors__first_name__icontains=query) | Q(authors__last_name__icontains=query) ) results = Book.objects.filter(qset).distinct() else: results = [] return render_to_response("books/search.html", { "results": results, "query": query })
There are a couple of things going on here that you havent yet seen. First, theres request.GET . This is how you access GET data from Django; POST data is accessed through a similar request.POST object. These objects behave exactly like standard Python dictionaries with some extra features covered in Appendix H.
杩欓噷鏈変竴浜涢渶瑕佹敞鎰忕殑锛岄鍏 request.GET 锛岃繖浠嶥jango涓庢牱璁块棶GET鏁版嵁锛汸OST鏁版嵁閫氳繃绫讳技鐨 request.POST 瀵硅薄璁块棶銆傝繖浜涘璞¤涓轰笌鏍囧噯Python瀛楀吀寰堝儚锛屽湪闄勫綍H涓垪鍑烘潵鍏跺彟澶栫殑鐗规с
Whats GET and POST Data?
浠涔堟槸 GET and POST 鏁版嵁?
GET and POST are the two methods that browsers use to send data to a server. Most of the time, youll see them in HTML form tags:
GET 鍜孭OST 鏄祻瑙堝櫒浣跨敤鐨勪袱涓柟娉曪紝鐢ㄤ簬鍙戦佹暟鎹埌鏈嶅姟鍣ㄧ銆 涓鑸潵璇达紝浼氬湪html琛ㄥ崟閲岄潰鐪嬪埌:
<form action="/books/search/" method="get">
This instructs the browser to submit the form data to the URL /books/search/ using the GET method.
瀹冩寚绀烘祻瑙堝櫒鍚/books/search/浠ET鐨勬柟娉曟彁浜ゆ暟鎹
There are important differences between the semantics of GET and POST that we wont get into right now, but see http://www.w3.org/2001/tag/doc/whenToUseGet.html if you want to learn more.
鍏充簬GET鍜孭OST杩欎袱涓柟娉曚箣闂存湁寰堝ぇ鐨勪笉鍚岋紝涓嶈繃鎴戜滑鏆傛椂涓嶆繁鍏ュ畠锛屽鏋滀綘鎯充簡瑙f洿澶氾紝鍙互璁块棶锛 http://www.w3.org/2001/tag/doc/whenToUseGet.html 銆
So the line:
鎵浠ヤ笅闈㈣繖琛岋細
query = request.GET.get('q', '')
looks for a GET parameter named q and returns an empty string if that parameter wasnt submitted.
瀵绘壘鍚嶄负 q 鐨凣ET鍙傛暟锛岃屼笖濡傛灉鍙傛暟娌℃湁鎻愪氦锛岃繑鍥炰竴涓┖鐨勫瓧绗︿覆銆
Note that were using the get() method on request.GET , which is potentially confusing. The get() method here is the one that every Python dictionary has. Were using it here to be careful: it is not safe to assume that request.GET contains a 'q' key, so we use get('q', '') to provide a default fallback value of '' (the empty string). If we merely accessed the variable using request.GET['q'] , that code would raise a KeyError if q wasnt available in the GET data.
娉ㄦ剰鍦 request.GET 涓娇鐢ㄤ簡 get() 鏂规硶锛岃繖鍙兘璁╁ぇ瀹朵笉濂界悊瑙c傝繖閲岀殑 get() 鏄瘡涓猵ython鐨勭殑瀛楀吀鏁版嵁绫诲瀷閮芥湁鐨勬柟娉曘備娇鐢ㄧ殑鏃跺欒灏忓績锛氬亣璁 request.GET 鍖呭惈涓涓 'q' 鐨刱ey鏄笉瀹夊叏鐨勶紝鎵浠ユ垜浠娇鐢 get('q', '') 鎻愪緵涓涓己鐪佺殑杩斿洖鍊 '' (涓涓┖瀛楃涓)銆傚鏋滃彧鏄娇鐢 request.GET['q'] 璁块棶鍙橀噺锛屽湪Get鏁版嵁鏃 q 涓嶅彲寰,鍙兘寮曞彂 KeyError .
Second, what about this Q business? Q objects are used to build up complex queries in this case, were searching for any books where either the title or the name of one of the authors matches the search query. Technically, these Q objects comprise a QuerySet, and you can read more about them in Appendix C.
鍏舵,鍏充簬 Q , Q 瀵硅薄鍦ㄨ繖涓緥瀛愰噷鐢ㄤ簬寤虹珛澶嶆潅鐨勬煡璇,鎼滅储鍖归厤鏌ヨ鐨勪换浣曚功绫.鎶鏈笂 Q 瀵硅薄鍖呭惈QuerySet,鍙互鍦ㄩ檮褰旵涓繘涓姝ラ槄璇.
In these queries, icontains is a case-insensitive search that uses the SQL LIKE operator in the underlying database.
鍦ㄨ繖涓煡璇腑锛 icontains 浣跨敤SQL鐨 LIKE 鎿嶄綔绗︼紝鏄ぇ灏忓啓涓嶆晱鎰熺殑銆
Since were searching against a many-to-many field, its possible for the same book to be returned more than once by the query (e.g., a book with two authors who both match the search query). Adding .distinct() to the filter lookup eliminates any duplicate results.
鏃㈢劧鎼滅储渚濋潬澶氬澶氬煙鏉ュ疄鐜帮紝灏辨湁鍙兘瀵瑰悓涓鏈功杩斿洖澶氭鏌ヨ缁撴灉锛堜緥濡傦細涓鏈功鏈変袱涓綔鑰呴兘绗﹀悎鏌ヨ鏉′欢锛夈傚洜姝ゆ坊鍔 .distinct() 杩囨护鏌ヨ缁撴灉锛屾秷闄ら噸澶嶉儴鍒嗐
Theres still no template for this search view, however. This should do the trick:
鐜板湪浠嶇劧娌℃湁杩欎釜鎼滅储瑙嗗浘鐨勬ā鏉匡紝鍙互濡備笅瀹炵幇:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>Search{% if query %} Results{% endif %}</title> </head> <body> <h1>Search</h1> <form action="." method="GET"> <label for="q">Search: </label> <input type="text" name="q" value="{{ query|escape }}"> <input type="submit" value="Search"> </form> {% if query %} <h2>Results for "{{ query|escape }}":</h2> {% if results %} <ul> {% for book in results %} <li>{{ book|escape }}</l1> {% endfor %} </ul> {% else %} <p>No books found</p> {% endif %} {% endif %} </body> </html>
Hopefully by now what this does is fairly obvious. However, there are a few subtleties worth pointing out:
甯屾湜浣犲凡缁忓緢娓呮鍦版槑鐧借繖涓疄鐜般備笉杩囷紝鏈夊嚑涓粏鑺傞渶瑕佹寚鍑猴細
The forms action is . , which means the current URL. This is a standard best practice: dont use separate views for the form page and the results page; use a single one that serves the form and search results.
琛ㄥ崟鐨刟ction鏄 . 锛 琛ㄧず褰撳墠鐨刄RL銆傝繖鏄竴涓爣鍑嗙殑鏈浣虫儻甯稿鐞嗘柟寮忥細涓嶄娇鐢ㄧ嫭绔 鐨勮鍥惧垎鍒潵鏄剧ず琛ㄥ崟椤甸潰鍜岀粨鏋滈〉闈紱鑰屾槸浣跨敤鍗曚釜瑙嗗浘椤甸潰鏉ュ鐞嗚〃鍗曞苟鏄剧ず鎼滅储缁撴灉銆
We reinsert the value of the query back into the <input> . This lets readers easily refine their searches without having to retype what they searched for.
鎴戜滑鎶婅繑鍥炵殑鏌ヨ鍊奸噸鏂版彃鍏ュ埌 <input> 涓幓锛屼互渚夸簬璇昏呭彲浠ュ畬鍠勪粬浠殑鎼滅储鍐呭锛 鑰屼笉蹇呴噸鏂拌緭鍏ユ悳绱㈠唴瀹广
Everywhere query and book is used, we pass it through the escape filter to make sure that any potentially malicious search text is filtered out before being inserted into the page.
鍦ㄦ墍鏈変娇鐢 query 鍜 book 鐨勫湴鏂癸紝鎴戜滑閫氳繃 escape 杩囨护鍣ㄦ潵纭繚浠讳綍 鍙兘鐨勬伓鎰忕殑鎼滅储鏂囧瓧琚繃婊ゅ嚭鍘伙紝浠ヤ繚璇佷笉琚彃鍏ュ埌椤甸潰閲屻
Its vital that you do this with any user-submitted content! Otherwise you open your site up to cross-site scripting (XSS) attacks. Chapter 19 discusses XSS and security in more detail.
杩欏澶勭悊浠讳綍鐢ㄦ埛鎻愪氦鏁版嵁鏉ヨ鏄 蹇呴』 鐨勶紒鍚﹀垯鐨勮瘽浣犲氨寮鏀句綘鐨勭綉绔欏厑璁歌法绔欑偣鑴氭湰 锛圶SS锛夋敾鍑汇傚湪绗崄涔濈珷涓皢璇︾粏璁ㄨ浜哫SS鍜屽畨鍏ㄣ
However, we dont need to worry about harmful content in your database lookups we can simply pass the query into the lookup as is. This is because Djangos database layer handles this aspect of security for you.
涓嶈繃锛屾垜浠笉蹇呮媴蹇冩暟鎹簱瀵瑰彲鑳芥湁鍗卞鍐呭鐨勬煡璇㈢殑澶勭悊銆 Django鐨勬暟鎹簱灞傚湪杩欐柟闈㈠凡缁忓仛杩囧畨鍏ㄥ鐞嗐 銆愯瘧娉細鏁版嵁搴撳眰瀵规煡璇㈡暟鎹嚜鍔‥scape锛屾墍浠ヤ笉鐢ㄦ媴蹇冦
Now we have a working search. A further improvement would be putting a search form on every page (i.e., in the base template); well let you handle that one yourself.
鐜板湪鎴戜滑宸茬粡浣滀簡鎼滅储銆傝繘涓姝ヨ鎶婃悳绱㈣〃鍗曞姞鍒版墍鏈夌殑椤甸潰锛堜緥濡傦紝鍦╞ase妯℃澘锛夛紱杩欎釜鍙互鐢变綘鑷繁瀹屾垚銆
Next, well look at a more complex example. But before we do, lets discuss a more abstract topic: the perfect form.
涓嬮潰锛屾垜浠湅涓涓嬫洿澶嶆潅鐨勪緥瀛愩備簨鍏堟垜浠璁轰竴涓娊璞$殑璇濋锛氬畬缇庤〃鍗曘
瀹岀編琛ㄥ崟
Forms can often be a major cause of frustration for the users of your site. Lets consider the behavior of a hypothetical perfect form:
琛ㄥ崟缁忓父寮曡捣绔欑偣鐢ㄦ埛鐨勫弽鎰熴傛垜浠冭檻涓涓嬩竴涓亣璁剧殑瀹岀編鐨勮〃鍗曠殑琛屼负锛
It should ask the user for some information, obviously. Accessibility and usability matter here, so smart use of the HTML <label> element and useful contextual help are important.
瀹冨簲璇ラ棶鐢ㄦ埛涓浜涗俊鎭紝鏄剧劧锛岀敱浜庡彲鐢ㄦх殑闂锛 浣跨敤HTML <label> 鍏冪礌鍜屾湁鐢ㄧ殑 涓婁笅鏂囧府鍔╂槸寰堥噸瑕佺殑銆
The submitted data should be subjected to extensive validation. The golden rule of Web application security is never trust incoming data, so validation is essential.
鎵鎻愪氦鐨勬暟鎹簲璇ュ鏂归潰鐨勯獙璇併俉eb搴旂敤瀹夊叏鐨勯噾绉戠帀寰嬫槸浠庝笉瑕佺浉淇¤繘鏉ョ殑鏁版嵁锛屾墍浠ラ獙璇佹槸蹇呴渶鐨勩
If the user has made any mistakes, the form should be redisplayed with detailed, informative error messages. The original data should be prefilled, to save the user from having to reenter everything.
濡傛灉鐢ㄦ埛鏈変竴浜涢敊璇紝琛ㄥ崟搴旇閲嶆柊鏄剧ず璇︽儏锛岄敊璇俊鎭傚師鏉ョ殑鏁版嵁搴旇宸茬粡濉ソ锛岄伩鍏嶇敤鎴烽噸鏂板綍鍏ワ紝
The form should continue to redisplay until all of the fields have been correctly filled.
琛ㄥ崟搴旇鍦ㄦ墍鏈夊煙楠岃瘉姝g‘鍓嶄竴鐩撮噸鏂版樉绀恒
Constructing the perfect form seems like a lot of work! Thankfully, Djangos forms framework is designed to do most of the work for you. You provide a description of the forms fields, validation rules, and a simple template, and Django does the rest. The result is a perfect form with very little effort.
寤虹珛杩欐牱鐨勮〃鍗曞ソ鍍忛渶瑕佸仛寰堝宸ヤ綔锛佸垢濂斤紝Django鐨勮〃鍗曟鏋跺凡缁忚璁$殑鍙互涓轰綘鍋氱粷澶ч儴鍒嗙殑宸ヤ綔銆備綘鍙渶瑕佹彁渚涜〃鍗曞煙鐨勬弿杩帮紝楠岃瘉瑙勫垯鍜岀畝鍗曠殑妯℃澘鍗冲彲銆傝繖鏍峰氨鍙渶瑕佷竴鐐圭殑宸ヤ綔灏卞彲浠ュ仛鎴愪竴涓畬缇庣殑琛ㄥ崟銆
鍒涘缓涓涓洖棣堣〃鍗
The best way to build a site that people love is to listen to their feedback. Many sites appear to have forgotten this; they hide their contact details behind layers of FAQs, and they seem to make it as difficult as possible to get in touch with an actual human being.
鍋氬ソ涓涓綉绔欓渶瑕佹敞鎰忕敤鎴风殑鍙嶉锛屽緢澶氱珯鐐瑰ソ鍍忓繕璁拌繖涓備粬浠妸鑱旂郴淇℃伅鏀惧湪FAQ鍚庨潰锛岃屼笖濂藉儚寰堥毦鑱旂郴鍒板疄闄呯殑浜恒
When your site has millions of users, this may be a reasonable strategy. When youre trying to build up an audience, though, you should actively encourage feedback at every opportunity. Lets build a simple feedback form and use it to illustrate Djangos forms framework in action.
涓涓櫨涓囩敤鎴风骇鐨勭綉绔欙紝鍙兘鏈変簺鍚堢悊鐨勭瓥鐣ャ傚鏋滃缓绔嬩竴涓潰鍚戠敤鎴风殑绔欑偣锛岄渶瑕侀紦鍔卞洖棣堛傛垜浠缓绔嬩竴涓畝鍗曠殑鍥為琛ㄥ崟锛岀敤鏉ュ睍绀篋jango鐨勮〃鍗曟鏋躲
Well start by adding adding (r'^contact/$', 'mysite.books.views.contact') to the URLconf, then defining our form. Forms in Django are created in a similar way to models: declaratively, using a Python class. Heres the class for our simple form. By convention, well insert it into a new forms.py file within our application directory:
寮濮嬶紝鍦║RLconf閲屾坊鍔 (r'^contact/$', 'mysite.books.views.contact') 锛岀劧鍚庡畾涔夎〃鍗曘 鍦―jango涓〃鍗曠殑鍒涘缓绫讳技MODEL:浣跨敤Python绫绘潵澹版槑銆傝繖閲屾槸鎴戜滑绠鍗曡〃鍗曠殑绫汇備负浜嗘柟渚匡紝鎶婂畠鍐欏埌鏂扮殑 forms.py 鏂囦欢涓紝杩欎釜鏂囦欢鍦╝pp鐩綍涓嬨
from django import newforms as forms TOPIC_CHOICES = ( ('general', 'General enquiry'), ('bug', 'Bug report'), ('suggestion', 'Suggestion'), ) class ContactForm(forms.Form): topic = forms.ChoiceField(choices=TOPIC_CHOICES) message = forms.CharField() sender = forms.EmailField(required=False)
New Forms? What?
New Forms鏄粈涔堬紵
When Django was first released to the public, it had a complicated, confusing forms system. It made producing forms far too difficult, so it was completely rewritten and is now called newforms. However, theres still a fair amount of code that depends on the old form system, so for the time being Django ships with two form packages.
褰揇jango鏈鍒濇帹鍑虹殑鏃跺欙紝鏈変竴涓鏉傝岄毦鐢ㄧ殑form绯荤粺銆傜敤瀹冩潵鏋勫缓琛ㄥ崟绠鐩村氨鏄櫓姊︼紝鎵浠ュ畠鍦ㄦ柊鐗堟湰閲岄潰琚竴涓彨鍋歯ewforms鐨勭郴缁熷彇浠d簡銆備絾鏄壌浜庤繕鏈夊緢澶氫唬鐮佷緷璧栦簬鑰佺殑閭d釜form绯荤粺锛屾殏鏃禗jango杩樻槸鍚屾椂淇濇湁涓や釜forms鍖呫
As we write this book, Djangos old form system is still available as django.forms and the new form package as django.newforms . At some point that will change and django.forms will point to the new form package. However, to make sure the examples in this book work as widely as possible, all the examples will refer to django.newforms .
鍦ㄦ湰涔﹀啓浣滄湡闂达紝Django鐨勮乫orm绯荤粺杩樻槸鍦 django.forms 涓紝鏂扮殑form绯荤粺浣嶄簬 django.newforms 涓傝繖绉嶇姸鍐佃繜鏃╀細鏀瑰彉锛 django.forms 浼氭寚鍚戞柊鐨刦orm鍖呫 浣嗘槸涓轰簡璁╂湰涔︿腑鐨勪緥瀛愬敖鍙兘骞挎硾鍦板伐浣滐紝鎵鏈夌殑浠g爜涓粛鐒朵細浣跨敤 django.newforms 銆
A Django form is a subclass of django.newforms.Form , just as a Django model is a subclass of django.db.models.Model . The django.newforms module also contains a number of Field classes; a full list is available in Djangos documentation at http://www.djangoproject.com/documentation/0.96/newforms/.
涓涓狣jango琛ㄥ崟鏄 django.newforms.Form 鐨勫瓙绫伙紝灏卞儚Django妯″瀷鏄 django.db.models.Model 鐨勫瓙绫讳竴鏍枫傚湪django.newforms妯″潡涓繕鍖呭惈寰堝Field绫伙紱Django鐨勬枃妗o紙 http://www.djangoproject.com/documentation/0.96/newforms/ 锛変腑鍖呭惈浜嗕竴涓彲鐢ㄧ殑Field鍒楄〃銆
Our ContactForm consists of three fields: a topic, which is a choice among three options; a message, which is a character field; and a sender, which is an email field and is optional (because even anonymous feedback can be useful). There are a number of other field types available, and you can write your own if they dont cover your needs.
鎴戜滑鐨 ContactForm 鍖呭惈涓変釜瀛楁锛氫竴涓猼opic锛屽畠鏄竴涓笁閫変竴鐨勯夋嫨妗嗭紱涓涓猰essage锛屽畠鏄竴涓枃鏈煙锛涜繕鏈変竴涓猻ender锛屽畠鏄竴涓彲閫夌殑email鍩燂紙鍥犱负鍗充娇鏄尶鍚嶅弽棣堜篃鏄湁鐢ㄧ殑锛夈傝繕鏈夊緢澶氬瓧娈电被鍨嬪彲渚涢夋嫨锛屽鏋滃畠浠兘涓嶆弧瓒宠姹傦紝浣犲彲浠ヨ冭檻鑷繁鍐欎竴涓
The form object itself knows how to do a number of useful things. It can validate a collection of data, it can generate its own HTML widgets, it can construct a set of useful error messages and, if were feeling lazy, it can even draw the entire form for us. Lets hook it into a view and see it in action. In views.py :
form瀵硅薄鑷繁鐭ラ亾濡備綍鍋氫竴浜涙湁鐢ㄧ殑浜嬫儏銆傚畠鑳芥牎楠屾暟鎹泦鍚堬紝鐢熸垚HTML鈥滈儴浠垛濓紝鐢熸垚涓闆嗘湁鐢ㄧ殑閿欒淇℃伅锛屽綋鐒讹紝濡傛灉浣犵‘瀹炲緢鎳掞紝瀹冧篃鑳界粯鍑烘暣涓猣orm銆傜幇鍦ㄨ鎴戜滑鎶婂畠宓屽叆涓涓鍥撅紝鐪嬬湅鎬庝箞鏍蜂娇鐢ㄥ畠銆傚湪views.py閲岄潰锛
from django.db.models import Q from django.shortcuts import render_to_response from models import Book **from forms import ContactForm** def search(request): query = request.GET.get('q', '') if query: qset = ( Q(title__icontains=query) | Q(authors__first_name__icontains=query) | Q(authors__last_name__icontains=query) ) results = Book.objects.filter(qset).distinct() else: results = [] return render_to_response("books/search.html", { "results": results, "query": query }) **def contact(request):** **form = ContactForm()** **return render_to_response('contact.html', {'form': form})**
and in contact.html :
娣诲姞contact.html鏂囦欢锛
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>Contact us</title> </head> <body> <h1>Contact us</h1> <form action="." method="POST"> <table> {{ form.as_table }} </table> <p><input type="submit" value="Submit"></p> </form> </body> </html>
The most interesting line here is {{ form.as_table }} . form is our ContactForm instance, as passed to render_to_response . as_table is a method on that object that renders the form as a sequence of table rows (as_ul and as_p can also be used). The generated HTML looks like this:
鏈鏈夋剰鎬濈殑涓琛屾槸 {{ form.as_table }}銆俧orm鏄疌ontactForm鐨勪竴涓疄渚嬶紝鎴戜滑閫氳繃render_to_response鏂规硶鎶婂畠浼犻掔粰妯℃澘銆俛s_table鏄痜orm鐨勪竴涓柟娉曪紝瀹冩妸form娓叉煋鎴愪竴绯诲垪鐨勮〃鏍艰(as_ul鍜宎s_p涔熸槸璧风潃鐩镐技鐨勪綔鐢)銆傜敓鎴愮殑HTML鍍忚繖鏍凤細
<tr> <th><label for="id_topic">Topic:</label></th> <td> <select name="topic" id="id_topic"> <option value="general">General enquiry</option> <option value="bug">Bug report</option> <option value="suggestion">Suggestion</option> </select> </td> </tr> <tr> <th><label for="id_message">Message:</label></th> <td><input type="text" name="message" id="id_message" /></td> </tr> <tr> <th><label for="id_sender">Sender:</label></th> <td><input type="text" name="sender" id="id_sender" /></td> </tr>
Note that the <table> and <form> tags are not included; you need to define those yourself in the template, which gives you control over how the form behaves when it is submitted. Label elements are included, making forms accessible out of the box.
璇锋敞鎰忥細<table>鍜<form>鏍囩骞舵病鏈夊寘鍚湪鍐咃紱鎴戜滑闇瑕佸湪妯℃澘閲屽畾涔夊畠浠紝杩欑粰浜堟垜浠洿澶х殑鎺у埗鏉冨幓鍐冲畾form鎻愪氦鏃剁殑琛屼负銆侺abel鍏冪礌鏄寘鍚湪鍐呯殑锛屼护璁块棶鎬ф洿浣筹紙鍥犱负label鐨勫间細鏄剧ず鍦ㄩ〉闈笂锛夈
Our form is currently using a <input type="text"> widget for the message field. We dont want to restrict our users to a single line of text, so well swap in a <textarea> widget instead:
鎴戜滑鐨刦orm鐜板湪浣跨敤浜嗕竴涓<input type=”text”>閮ㄤ欢鏉ユ樉绀簃essage瀛楁銆備絾鎴戜滑涓嶆兂闄愬埗鎴戜滑鐨勭敤鎴峰彧鑳借緭鍏ヤ竴琛屾枃鏈紝鎵浠ユ垜浠敤涓涓<textarea>閮ㄤ欢鏉ユ浛浠o細
class ContactForm(forms.Form): topic = forms.ChoiceField(choices=TOPIC_CHOICES) message = forms.CharField(**widget=forms.Textarea()** ) sender = forms.EmailField(required=False)
The forms framework separates out the presentation logic for each field into a set of widgets. Each field type has a default widget, but you can easily override the default, or provide a custom widget of your own.
forms妗嗘灦鎶婃瘡涓涓瓧娈电殑鏄剧ず閫昏緫鍒嗙鍒颁竴缁勯儴浠讹紙widget锛変腑銆傛瘡涓涓瓧娈电被鍨嬮兘鎷ユ湁涓涓粯璁ょ殑閮ㄤ欢锛屾垜浠篃鍙互瀹规槗鍦版浛鎹㈡帀榛樿鐨勯儴浠讹紝鎴栬呮彁渚涗竴涓嚜瀹氫箟鐨勯儴浠躲
At the moment, submitting the form doesnt actually do anything. Lets hook in our validation rules:
鐜板湪锛屾彁浜よ繖涓猣orm娌℃湁鍦ㄥ悗鍙板仛浠讳綍浜嬫儏銆傝鎴戜滑鎶婃垜浠殑鏍¢獙瑙勫垯鍔犺繘鍘伙細
def contact(request): if request.method == 'POST': form = ContactForm(request.POST) else: form = ContactForm() return render_to_response('contact.html', {'form': form})
A form instance can be in one of two states: bound or unbound. A bound instance is constructed with a dictionary (or dictionary-like object) and knows how to validate and redisplay the data from it. An unbound form has no data associated with it and simply knows how to display itself.
涓涓猣orm瀹炰緥鍙兘澶勫湪涓ょ鐘舵侊細缁戝畾鎴栬呮湭缁戝畾銆備竴涓粦瀹氱殑瀹炰緥鏄敱瀛楀吀锛堟垨鑰呯被浼间簬瀛楀吀鐨勫璞★級鏋勯犺屾潵鐨勶紝瀹冨悓鏍蜂篃鐭ラ亾濡備綍楠岃瘉鍜岄噸鏂版樉绀哄畠鐨勬暟鎹備竴涓湭缁戝畾鐨刦orm鏄病鏈変笌涔嬭仈绯荤殑鏁版嵁锛屼粎浠呯煡閬撳浣曟樉绀哄叾鑷韩銆
Try clicking Submit on the blank form. The page should redisplay, showing a validation error that informs us that our message field is required.
鐜板湪鍙互璇曠潃鎻愪氦涓涓嬭繖涓┖鐧界殑form浜嗐傞〉闈㈠皢浼氳閲嶆柊鏄剧ず鍑烘潵锛屾樉绀轰竴涓獙璇侀敊璇紝鎻愮ず鎴戜滑message瀛楁鏄繀椤荤殑銆
Try entering an invalid email address as well. The EmailField knows how to validate email addresses, at least to a reasonable level of doubt.
鐜板湪杈撳叆涓涓笉鍚堟硶鐨別mail鍦板潃锛孍mailField鐭ラ亾濡備綍楠岃瘉email鍦板潃锛屽ぇ澶氭暟鎯呭喌涓嬭繖绉嶉獙璇佹槸鍚堢悊鐨勩
Setting Initial Data
璁剧疆鍒濆鏁版嵁
Passing data directly to the form constructor binds that data and indicates that validation should be performed. Often, though, we need to display an initial form with some of the fields prefilled for example, an edit form. We can do this with the initial keyword argument:
鍚慺orm鐨勬瀯閫犲櫒鍑芥暟鐩存帴浼犻掓暟鎹細鎶婅繖浜涙暟鎹粦瀹氬埌form锛屾寚绀篺orm杩涜楠岃瘉銆傛垜浠湁鏃朵篃闇瑕佸湪鍒濆鍖栫殑鏃跺欓鍏堝~鍏呬竴浜涘瓧娈碘斺旀瘮鏂硅涓涓紪杈慺orm銆傛垜浠彲浠ヤ紶鍏ヤ竴浜涘垵濮嬬殑鍏抽敭瀛楀弬鏁帮細
form = CommentForm(initial={'sender': 'user@example.com'})
If our form will always use the same default values, we can configure them in the form definition itself:
濡傛灉鎴戜滑鐨刦orm鎬绘槸浼氫娇鐢ㄧ浉鍚岀殑榛樿鍊硷紝鎴戜滑鍙互鍦╢orm鑷韩鐨勫畾涔変腑璁剧疆瀹冧滑
message = forms.CharField(widget=forms.Textarea(), **initial="Replace with your feedback"** )
澶勭悊鎻愪氦
Once the user has filled the form to the point that it passes our validation rules, we need to do something useful with the data. In this case, we want to construct and send an email containing the users feedback. Well use Djangos email package to do this.
褰撶敤鎴峰~瀹宖orm锛屽畬鎴愪簡鏍¢獙锛屾垜浠渶瑕佸仛涓浜涙湁鐢ㄧ殑浜嬫儏浜嗐傚湪鏈緥涓紝鎴戜滑闇瑕佹瀯閫犲苟鍙戦佷竴涓寘鍚簡鐢ㄦ埛鍙嶉鐨別mail锛屾垜浠皢浼氫娇鐢―jango鐨別mail鍖呮潵瀹屾垚
First, though, we need to tell if the data is indeed valid, and if it is, we need access to the validated data. The forms framework does more than just validate the data, it also converts it into Python types. Our contact form only deals with strings, but if we were to use an IntegerField or DateTimeField , the forms framework would ensure that we got back a Python integer or datetime object, respectively.
棣栧厛锛屾垜浠渶瑕佺煡閬撶敤鎴锋暟鎹槸涓嶆槸鐪熺殑鍚堟硶锛屽鏋滄槸杩欐牱锛屾垜浠氨瑕佽闂凡缁忛獙璇佽繃鐨勬暟鎹俧orms妗嗘灦鐢氳嚦鍋氱殑鏇村锛屽畠浼氭妸瀹冧滑杞崲鎴愬搴旂殑Python绫诲瀷銆傛垜浠殑鑱旂郴鏂瑰紡form浠呬粎澶勭悊瀛楃涓诧紝浣嗘槸濡傛灉鎴戜滑浣跨敤IntegerField鎴栬匘ataTimeField锛宖orms妗嗘灦浼氫繚璇佹垜浠粠涓彇寰楃被鍨嬫纭殑鍊笺
To tell whether a form is bound to valid data, call the is_valid() method:
娴嬭瘯涓涓猣orm鏄惁宸茬粡缁戝畾鍒板悎娉曠殑鏁版嵁锛屼娇鐢╥s_valid()鏂规硶锛
form = ContactForm(request.POST) if form.is_valid(): # Process form data
Now we need access to the data. We could pull it straight out of request.POST , but if we did, wed miss out on the type conversions performed by the forms framework. Instead, we use form.clean_data :
鐜板湪鎴戜滑瑕佽闂暟鎹簡銆傛垜浠彲浠ヤ粠request.POST閲岄潰鐩存帴鎶婂畠浠彇鍑烘潵锛屼絾鏄繖鏍峰仛鎴戜滑灏变抚澶变簡鐢眆ramework涓烘垜浠嚜鍔ㄥ仛绫诲瀷杞崲鐨勫ソ澶勪簡銆傛墍浠ユ垜浠浣跨敤form.clean_data:
if form.is_valid(): topic = form.clean_data['topic'] message = form.clean_data['message'] sender = form.clean_data.get('sender', 'noreply@example.com') # ...
Note that since sender is not required, we provide a default when its missing. Finally, we need to record the users feedback. The easiest way to do this is to email it to a site administrator. We can do that using the send_mail function:
璇锋敞鎰忓洜涓簊ender涓嶆槸蹇呴渶鐨勶紝鎴戜滑涓哄畠鎻愪緵浜嗕竴涓粯璁ゅ笺傜粓浜庯紝鎴戜滑瑕佽褰曚笅鐢ㄦ埛鐨勫弽棣堜簡锛屾渶绠鍗曠殑鏂规硶灏辨槸鎶婂畠鍙戦佺粰绔欑偣绠$悊鍛橈紝鎴戜滑鍙互浣跨敤send_mail鏂规硶锛
from django.core.mail import send_mail # ... send_mail( 'Feedback from your site, topic: %s' % topic, message, sender, ['administrator@example.com'] )
The send_mail function has four required arguments: the email subject, the email body, the from address, and a list of recipient addresses. send_mail is a convenient wrapper around Djangos EmailMessage class, which provides advanced features such as attachments, multipart emails, and full control over email headers.
send_mail鏂规硶鏈夊洓涓繀椤荤殑鍙傛暟锛氫富棰橈紝閭欢姝f枃锛宖rom鍜屼竴涓帴鍙楄呭垪琛ㄣ俿end_mail鏄疍jango鐨凟mailMessage绫荤殑涓涓柟渚跨殑鍖呰锛孍mailMessage绫绘彁渚涗簡鏇撮珮绾х殑鏂规硶锛屾瘮濡傞檮浠讹紝澶氶儴鍒嗛偖浠讹紝浠ュ強瀵逛簬閭欢澶撮儴鐨勫畬鏁存帶鍒躲 鍙戦佸畬閭欢涔嬪悗锛屾垜浠細鎶婄敤鎴烽噸瀹氬悜鍒扮‘璁ょ殑椤甸潰銆傚畬鎴愪箣鍚庣殑瑙嗗浘鏂规硶濡備笅锛
Having sent the feedback email, well redirect our user to a static confirmation page. The finished view function looks like this:
鍙戦佸畬閭欢涔嬪悗锛屾垜浠細鎶婄敤鎴烽噸瀹氬悜鍒扮‘璁ょ殑椤甸潰銆傚畬鎴愪箣鍚庣殑瑙嗗浘鏂规硶濡備笅锛
from django.http import HttpResponseRedirect from django.shortcuts import render_to_response from django.core.mail import send_mail from forms import ContactForm def contact(request): if request.method == 'POST': form = ContactForm(request.POST) if form.is_valid(): topic = form.clean_data['topic'] message = form.clean_data['message'] sender = form.clean_data.get('sender', 'noreply@example.com') send_mail( 'Feedback from your site, topic: %s' % topic, message, sender, ['administrator@example.com'] ) return HttpResponseRedirect('/contact/thanks/') else: form = ContactForm() return render_to_response('contact.html', {'form': form})
Redirect After POST
鍦≒OST涔嬪悗绔嬪嵆閲嶅畾鍚
If a user selects Refresh on a page that was displayed by a POST request, that request will be repeated. This can often lead to undesired behavior, such as a duplicate record being added to the database. Redirect after POST is a useful pattern that can help avoid this scenario: after a successful POST has been processed, redirect the user to another page rather than returning HTML directly.
鍦ㄤ竴涓狿OST璇锋眰杩囧悗锛屽鏋滅敤鎴烽夋嫨鍒锋柊椤甸潰锛岃繖涓姹傚氨閲嶅鎻愪氦浜嗐傝繖甯稿父浼氬鑷存垜浠笉甯屾湜鐨勮涓猴紝姣斿閲嶅鐨勬暟鎹簱璁板綍銆傚湪POST涔嬪悗閲嶅畾鍚戦〉闈㈡槸涓涓湁鐢ㄧ殑妯″紡锛屽彲浠ラ伩鍏嶈繖鏍风殑鎯呭喌鍑虹幇锛氬湪涓涓狿OST璇锋眰鎴愬姛鐨勫鐞嗕箣鍚庯紝鎶婄敤鎴峰寮曞埌鍙﹀涓涓〉闈笂鍘伙紝鑰屼笉鏄洿鎺ヨ繑鍥濰TML椤甸潰銆
1d0p2u <a href=”http://azetemwaeinp.com/“>azetemwaeinp</a>, [url=http://lcaytpsbsxkh.com/]lcaytpsbsxkh[/url], [link=http://hgjnhjgnqlch.com/]hgjnhjgnqlch[/link], http://curhltadaokb.com/
Imagine weve launched our feedback form, and the emails have started tumbling in. Theres just one problem: some of the emails are just one or two words, hardly enough for a detailed missive. We decide to adopt a new validation policy: four words or more, please.
鍋囪鎴戜滑宸茬粡鍙戝竷浜嗗弽棣堥〉闈簡锛宔mail宸茬粡寮濮嬫簮婧愪笉鏂湴娑屽叆浜嗐傚彧鏈変竴涓棶棰橈細涓浜沞mail鍙湁瀵ュ鏁拌锛屽緢闅句粠涓緱鍒颁粈涔堣缁嗘湁鐢ㄧ殑淇℃伅銆傛墍浠ユ垜浠喅瀹氬鍔犱竴鏉℃柊鐨勬牎楠岋細鏉ョ偣涓撲笟绮剧锛屾渶璧风爜鍐欏洓涓瓧锛屾嫓鎵樸
There are a number of ways to hook custom validation into a Django form. If our rule is something we will reuse again and again, we can create a custom field type. Most custom validations are one-off affairs, though, and can be tied directly to the form class.
鎴戜滑鏈夊緢澶氱殑鏂规硶鎶婃垜浠殑鑷畾涔夋牎楠屾寕鍦―jango鐨刦orm涓娿傚鏋滄垜浠殑瑙勫垯浼氳涓娆″張涓娆$殑浣跨敤锛屾垜浠彲浠ュ垱寤轰竴涓嚜瀹氫箟鐨勫瓧娈电被鍨嬨傚ぇ澶氭暟鐨勮嚜瀹氫箟鏍¢獙閮芥槸涓娆℃х殑锛屽彲浠ョ洿鎺ョ粦瀹氬埌form绫.
We want additional validation on the message field, so we need to add a clean_message method to our form:
鎴戜滑甯屾湜message瀛楁鏈変竴涓澶栫殑鏍¢獙锛屾垜浠鍔犱竴涓猚lean_message鏂规硶锛
class ContactForm(forms.Form): topic = forms.ChoiceField(choices=TOPIC_CHOICES) message = forms.CharField(widget=forms.Textarea()) sender = forms.EmailField(required=False) def clean_message(self): message = self.clean_data.get('message', '') num_words = len(message.split()) if num_words < 4: raise forms.ValidationError("Not enough words!") return message
This new method will be called after the default field validator (in this case, the validator for a required CharField ). Because the field data has already been partially processed, we need to pull it out of the forms clean_data dictionary.
杩欎釜鏂扮殑鏂规硶灏嗗湪榛樿鐨勫瓧娈垫牎楠屽櫒涔嬪悗琚皟鐢紙鍦ㄦ湰渚嬩腑锛屽氨鏄疌harField鐨勬牎楠屽櫒锛夈傚洜涓哄瓧娈垫暟鎹凡缁忚閮ㄥ垎鍦板鐞嗘帀浜嗭紝鎴戜滑闇瑕佷粠form鐨刢lean_data瀛楀吀涓妸瀹冨紕鍑烘潵銆
We naively use a combination of len() and split() to count the number of words. If the user has entered too few words, we raise a ValidationError . The string attached to this exception will be displayed to the user as an item in the error list.
鎴戜滑绠鍗曞湴浣跨敤浜唋en()鍜宻plit()鐨勭粍鍚堟潵璁$畻鍗曡瘝鐨勬暟閲忋傚鏋滅敤鎴疯緭鍏ヤ簡杩囧皯鐨勮瘝锛屾垜浠墧鍑轰竴涓猇alidationError銆傝繖涓猠xception鐨勯敊璇俊鎭細琚樉绀哄湪閿欒鍒楄〃閲屻
It is important that we explicitly return the value for the field at the end of the method. This allows us to modify the value (or convert it to a different Python type) within our custom validation method. If we forget the return statement, then None will be returned, and the original value will be lost.
鍦ㄥ嚱鏁扮殑鏈熬鏄惧紡鍦拌繑鍥炲瓧娈电殑鍊奸潪甯搁噸瑕併傛垜浠彲浠ュ湪鎴戜滑鑷畾涔夌殑鏍¢獙鏂规硶涓慨鏀瑰畠鐨勫硷紙鎴栬呮妸瀹冭浆鎹㈡垚鍙︿竴绉峆ython绫诲瀷锛夈傚鏋滄垜浠繕璁颁簡杩欎竴姝ワ紝None鍊煎氨浼氳繑鍥烇紝鍘熷鐨勬暟鎹氨涓㈠け鎺変簡銆
The quickest way to customize the forms presentation is with CSS. The list of errors in particular could do with some visual enhancement, and the <ul> has a class attribute of errorlist for that exact purpose. The following CSS really makes our errors stand out:
淇敼form鐨勬樉绀虹殑鏈蹇嵎鐨勬柟寮忔槸浣跨敤CSS銆傞敊璇殑鍒楄〃鍙互鍋氫竴浜涜瑙変笂鐨勫寮猴紝<ul>鏍囩鐨刢lass灞炴т负浜嗚繖涓洰鐨勩備笅闈㈢殑CSS璁╅敊璇洿鍔犻啋鐩簡锛
<style type="text/css"> ul.errorlist { margin: 0; padding: 0; } .errorlist li { background-color: red; color: white; display: block; font-size: 10px; margin: 0 0 3px; padding: 4px 5px; } </style>
While its convenient to have our forms HTML generated for us, in many cases the default rendering wont be right for our application. {{ form.as_table }} and friends are useful shortcuts while we develop our application, but everything about the way a form is displayed can be overridden, mostly within the template itself.
铏界劧鎴戜滑鍙互鏂逛究鍦颁娇鐢╢orm鏉ョ敓鎴怘TML锛屽彲鏄粯璁ょ殑娓叉煋鍦ㄥ鏁版儏鍐典笅婊¤冻涓嶄簡鎴戜滑鐨勫簲鐢ㄣ倇{form.as_table}}鍜屽叾瀹冪殑鏂规硶鍦ㄥ紑鍙戠殑鏃跺欐槸涓涓揩鎹风殑鏂瑰紡锛宖orm鐨勬樉绀烘柟寮忎篃鍙互鍦╢orm涓鏂逛究鍦伴噸鍐欍
Each field widget (<input type="text"> , <select> , <textarea> , or similar) can be rendered individually by accessing {{ form.fieldname }} . Any errors associated with a field are available as {{ form.fieldname.errors }} . We can use these form variables to construct a custom template for our contact form:
姣忎竴涓瓧娈甸儴浠(<input type=”text”>, <select>, <textarea>, 鎴栬呯被浼)閮藉彲浠ラ氳繃璁块棶{{form.瀛楁鍚峿}杩涜鍗曠嫭鐨勬覆鏌撱備换浣曡窡瀛楁鐩稿叧鐨勯敊璇兘鍙互閫氳繃{{form.fieldname.errors}}璁块棶銆傛垜浠彲浠ュ悓杩欎簺form鐨勫彉閲忔潵涓烘垜浠殑琛ㄥ崟鏋勯犱竴涓嚜瀹氫箟鐨勬ā鏉匡細
<form action="." method="POST"> <div class="fieldWrapper"> {{ form.topic.errors }} <label for="id_topic">Kind of feedback:</label> {{ form.topic }} </div> <div class="fieldWrapper"> {{ form.message.errors }} <label for="id_message">Your message:</label> {{ form.message }} </div> <div class="fieldWrapper"> {{ form.sender.errors }} <label for="id_sender">Your email (optional):</label> {{ form.sender }} </div> <p><input type="submit" value="Submit"></p> </form>
{{ form.message.errors }} will display as a <ul class="errorlist"> if errors are present and a blank string if the field is valid (or the form is unbound). We can also treat form.message.errors as a Boolean or even iterate over it as a list, for example:
{{ form.message.errors }} 浼氬湪 <ul class="errorlist"> 閲岄潰鏄剧ず锛屽鏋滃瓧娈垫槸鍚堟硶鐨勶紝鎴栬協orm娌℃湁琚粦瀹氾紝灏辨樉绀轰竴涓┖瀛楃涓层傛垜浠繕鍙互鎶 form.message.errors 褰撲綔涓涓竷灏斿兼垨鑰呭綋瀹冩槸list鍦ㄤ笂闈㈠仛杩唬锛
<div class="fieldWrapper{% if form.message.errors %} errors{% endif %}"> {% if form.message.errors %} <ol> {% for error in form.message.errors %} <li><strong>{{ error|escape }}</strong></li> {% endfor %} </ol> {% endif %} {{ form.message }} </div>
In the case of validation errors, this will add an errors class to the containing <div> and display the list of errors in an ordered list.
鍦ㄦ牎楠屽け璐ョ殑鎯呭喌涓, 杩欐浠g爜浼氬湪鍖呭惈閿欒瀛楁鐨刣iv鐨刢lass灞炴т腑澧炲姞涓涓”errors”锛屽湪涓涓湁搴忓垪琛ㄤ腑鏄剧ず閿欒淇℃伅銆
Lets build something a little more interesting: a form that submits a new publisher to our book application from Chapter 5.
鎴戜滑寮勪釜鏈夎叮鐨勪笢瑗垮惂锛氫竴涓柊鐨刦orm锛屾彁浜や竴涓柊鍑虹増鍟嗙殑淇℃伅鍒版垜浠浜旂珷鐨刡ook搴旂敤銆
An important rule of thumb in software development that Django tries to adhere to is Dont Repeat Yourself (DRY). Andy Hunt and Dave Thomas in The Pragmatic Programmer define this as follows:
涓涓潪甯搁噸瑕佺殑Django鐨勫紑鍙戠悊蹇靛氨鏄笉瑕侀噸澶嶄綘鑷繁(DRY)銆侫ny Hunt鍜孌ave Thomas鍦ㄣ婂疄鐢ㄤ富涔夌▼搴忓憳銆嬮噷瀹氫箟浜嗚繖涓師鍒欙細
Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
鍦ㄧ郴缁熷唴閮紝姣忎竴鏉★紙棰嗗煙鐩稿叧鐨勶級鐭ヨ瘑鐨勭墖鏂兘蹇呴』鏈変竴涓崟鐙殑锛屾棤姝т箟鐨勶紝姝e紡鐨勮〃杩般
Our Publisher model class says that a publisher has a name, address, city, state_province, country, and website. Duplicating this information in a form definition would break the DRY rule. Instead, we can use a useful shortcut: form_for_model() :
鎴戜滑鐨勫嚭鐗堝晢妯″瀷鎷ユ湁涓涓悕瀛楋紝鍦板潃锛屽煄甯傦紝宸烇紙鐪侊級锛屽浗瀹跺拰缃戠珯銆傚湪form涓噸澶嶈繖涓俊鎭棤鐤戣繚鍙嶄簡DRY鍘熷垯銆傛垜浠彲浠ヤ娇鐢ㄤ竴涓嵎寰勶細form_for_model()锛
from models import Publisher from django.newforms import form_for_model PublisherForm = form_for_model(Publisher)
PublisherForm is a Form subclass, just like the ContactForm class we created manually earlier on. We can use it in much the same way:
PublisherForm鏄竴涓狥orm瀛愮被锛屽儚鍒氬垰鎵嬪伐鍒涘缓鐨凜ontactForm绫讳竴鏍枫傛垜浠彲浠ュ儚鍒氭墠涓鏍蜂娇鐢ㄥ畠锛
from forms import PublisherForm def add_publisher(request): if request.method == 'POST': form = PublisherForm(request.POST) if form.is_valid(): form.save() return HttpResponseRedirect('/add_publisher/thanks/') else: form = PublisherForm() return render_to_response('books/add_publisher.html', {'form': form})
The add_publisher.html file is almost identical to our original contact.html template, so it has been omitted. Also remember to add a new pattern to the URLconf: (r'^add_publisher/$', 'mysite.books.views.add_publisher') .
add_publisher.html 鏂囦欢鍑犱箮璺熸垜浠殑contact.html妯℃澘涓鏍凤紝鎵浠ヤ笉璧樿堪浜嗐傝寰楀湪URLConf閲岄潰鍔犱笂锛 (r'^add_publisher/$', 'mysite.books.views.add_publisher') .
Theres one more shortcut being demonstrated here. Since forms derived from models are often used to save new instances of the model to the database, the form class created by form_for_model includes a convenient save() method. This deals with the common case; youre welcome to ignore it if you want to do something a bit more involved with the submitted data.
杩樻湁涓涓揩鎹风殑鏂规硶銆傚洜涓轰粠妯″瀷鑰屾潵鐨勮〃鍗曠粡甯歌鐢ㄦ潵鎶婃柊鐨勬ā鍨嬬殑瀹炰緥淇濆瓨鍒版暟鎹簱锛屼粠 form_for_model 鑰屾潵鐨勮〃鍗曞璞″寘鍚竴涓 save() 鏂规硶銆備竴鑸儏鍐典笅澶熺敤浜嗭紱浣犳兂瀵规彁浜ょ殑鏁版嵁浣滆繘涓姝ョ殑澶勭悊鐨勮瘽锛屾棤瑙嗗畠灏卞ソ浜嗐
form_for_instance() is a related method that can create a preinitialized form from an instance of a model class. This is useful for creating edit forms.
form_for_instance() 鏄彟澶栦竴涓柟娉曪紝鐢ㄤ簬浠庝竴涓ā鍨嬪璞′腑浜х敓涓涓垵濮嬪寲杩囩殑琛ㄥ崟瀵硅薄锛岃繖涓綋鐒剁粰鈥滅紪杈戔濊〃鍗曟彁渚涗簡鏂逛究銆
This chapter concludes the introductory material in this book. The next 13 chapters deal with various advanced topics, including generating content other than HTML (Chapter 11), security (Chapter 19), and deployment (Chapter 20).
杩欎竴绔犲凡缁忓畬鎴愪簡杩欐湰涔︾殑浠嬬粛鎬х殑鏉愭枡銆傛帴涓嬫潵鐨勫崄涓変釜绔犺妭璁ㄨ浜嗕竴浜涢珮绾х殑璇濋锛屽寘鎷敓鎴愰潪html鍐呭锛堢11绔狅級锛屽畨鍏紙绗19绔狅級鍜岄儴缃诧紙绗20绔狅級銆
After these first seven chapters, you should know enough to start writing your own Django projects. The rest of the material in this book will help fill in the missing pieces as you need them.
鍦ㄦ湰涔︽渶鍒濈殑涓冪珷鍚庯紝鎴戜滑锛堢粓浜庯級瀵逛簬浣跨敤Django鏋勫缓鑷繁鐨勭綉绔欏凡缁忕煡閬撶殑澶熷浜嗭紝鎺ヤ笅鏉ョ殑鍐呭鍙互鍦ㄩ渶瑕佺殑鏃跺欓槄璇汇
Well start in Chapter 8 by doubling back and taking a closer look at views and URLconfs (introduced first in Chapter 3).
绗叓绔犻噷鎴戜滑浼氭洿杩涗竴姝ュ湴浠嬬粛瑙嗗浘鍜孶RLConfs锛堜粙缁嶈绗笁绔狅級銆
鍏充簬鏈瘎娉ㄧ郴缁
鏈珯浣跨敤涓婁笅鏂囧叧鑱旂殑璇勬敞绯荤粺鏉ユ敹闆嗗弽棣堜俊鎭備笉鍚屼簬涓鑸鏁寸珷鍋氳瘎娉ㄧ殑鍋氭硶锛 鎴戜滑鍏佽浣犲姣忎竴涓嫭绔嬬殑鈥滄枃鏈潡鈥濆仛璇勬敞銆備竴涓滄枃鏈潡鈥濈湅璧锋潵鏄繖鏍风殑锛
涓涓滄枃鏈潡鈥濇槸涓涓钀斤紝涓涓垪琛ㄩ」锛屼竴娈典唬鐮侊紝鎴栬呭叾浠栦竴灏忔鍐呭銆 浣犻変腑瀹冧細楂樹寒搴︽樉绀:
瑕佸鏂囨湰鍧楀仛璇勬敞锛屼綘鍙渶瑕佺偣鍑诲畠鏃佽竟鐨勬爣璇嗗潡:
鎴戜滑浼氫粩缁嗛槄璇绘瘡涓瘎璁猴紝濡傛灉鍙兘鐨勮瘽鎴戜滑涔熶細鎶婅瘎娉ㄨ冭檻鍒版湭鏉ョ殑鐗堟湰涓幓:
濡傛灉浣犳効鎰忎綘鐨勮瘎娉ㄨ閲囩敤锛岃纭繚鐣欎笅浣犵殑鍏ㄥ悕 (娉ㄦ剰涓嶆槸鏄电О鎴栫畝绉帮級
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.