In Chapter 3, we covered the fundamentals of building dynamic Web sites with Django: setting up views and URLconfs. As we explained, a view is responsible for doing some arbitrary logic , and then returning a response. In the example, our arbitrary logic was to calculate the current date and time.
鍦ㄧ涓夌珷锛屾垜浠杩颁簡鐢 Django 寤洪犵綉绔欑殑鍩烘湰閫斿緞锛氬缓绔嬭鍥惧拰 URLConf 銆傛濡傛垜浠墍闃愯堪鐨勶紝瑙嗗浘璐熻矗澶勭悊 涓浜涗换鎰忛昏緫 锛岀劧鍚庤繑鍥炲搷搴旂粨鏋溿傚湪鑼冧緥涓紝鎴戜滑鐨勪换鎰忛昏緫灏辨槸璁$畻褰撳墠鐨勬棩鏈熷拰鏃堕棿銆
In modern Web applications, the arbitrary logic often involves interacting with a database. Behind the scenes, a database-driven Web site connects to a database server, retrieves some data out of it, and displays that data, nicely formatted, on a Web page. Or, similarly, the site could provide functionality that lets site visitors populate the database on their own.
鍦ㄥ綋浠 Web 搴旂敤涓紝浠绘剰閫昏緫缁忓父鐗垫秹鍒颁笌鏁版嵁搴撶殑浜や簰銆 鏁版嵁搴撻┍鍔ㄧ綉绔 鍦ㄥ悗鍙拌繛鎺ユ暟鎹簱鏈嶅姟鍣紝浠庝腑鍙栧嚭涓浜涙暟鎹紝鐒跺悗鍦 Web 椤甸潰鐢ㄦ紓浜殑鏍煎紡灞曠ず杩欎簺鏁版嵁銆傛垨鑰咃紝绔欑偣涔熸彁渚涜璁块棶鑰呰嚜琛屽~鍏呮暟鎹簱鐨勫姛鑳姐
Many complex Web sites provide some combination of the two. Amazon.com, for instance, is a great example of a database-driven site. Each product page is essentially a query into Amazons product database formatted as HTML, and when you post a customer review, it gets inserted into the database of reviews.
璁稿澶嶆潅鐨勭綉绔欓兘鎻愪緵浜嗕互涓婁袱涓姛鑳界殑鏌愮缁撳悎銆備緥濡 Amazon.com 灏辨槸涓涓暟鎹簱椹卞姩绔欑偣鐨勮壇濂借寖渚嬨傛湰璐ㄤ笂锛屾瘡涓骇鍝侀〉閮芥槸浠庢暟鎹簱涓彇鍑虹殑鏁版嵁琚牸寮忓寲涓 HTML锛岃屽綋浣犲彂琛ㄥ鎴疯瘎璁烘椂锛岃璇勮琚彃鍏ヨ瘎璁烘暟鎹簱涓
Django is well suited for making database-driven Web sites, as it comes with easy yet powerful ways of performing database queries using Python. This chapter explains that functionality: Djangos database layer.
鐢变簬鍏堝ぉ鍏峰 Python 绠鍗曡屽己澶х殑鏁版嵁搴撴煡璇㈡墽琛屾柟娉曪紝Django 闈炲父閫傚悎寮鍙戞暟鎹簱椹卞姩缃戠珯銆傛湰绔犳繁鍏ヤ粙缁嶄簡璇ュ姛鑳斤細Django 鏁版嵁搴撳眰銆
(Note: While its not strictly necessary to know basic database theory and SQL in order to use Djangos database layer, its highly recommended. An introduction to those concepts is beyond the scope of this book, but keep reading even if youre a database newbie. Youll probably be able to follow along and grasp concepts based on the context.)
锛堟敞鎰忥細灏界瀵 Django 鏁版嵁搴撳眰鐨勪娇鐢ㄤ腑骞朵笉鐗瑰埆寮鸿皟锛屾垜浠繕鏄己鐑堝缓璁帉鎻′竴浜涙暟鎹簱鍜 SQL 鍘熺悊銆傚杩欎簺姒傚康鐨勪粙缁嶈秴瓒婁簡鏈功鐨勮寖鍥达紝浣嗗氨绠椾綘鏄暟鎹簱鏂归潰鐨勮彍楦燂紝鎴戜滑涔熷缓璁綘缁х画闃呰銆備綘涔熻鑳藉璺熶笂杩涘害锛屽苟鍦ㄤ笂涓嬫枃瀛︿範杩囩▼涓帉鎻′竴浜涙蹇点傦級
Just as Chapter 3 detailed a dumb way to produce output within a view (by hard-coding the text directly within the view), theres a dumb way to retrieve data from a database in a view. Its simple: just use any existing Python library to execute an SQL query and do something with the results.
姝e绗笁绔犺缁嗕粙缁嶇殑閭d釜鍦ㄨ鍥句腑杈撳嚭 HTML 鐨勭鏂规硶锛堥氳繃鍦ㄨ鍥鹃噷瀵规枃鏈洿鎺ョ‖缂栫爜HTML锛夛紝鍦ㄨ鍥句腑涔熸湁绗ㄦ柟娉曞彲浠ヤ粠鏁版嵁搴撲腑鑾峰彇鏁版嵁銆傚緢绠鍗曪細鐢ㄧ幇鏈夌殑浠讳綍 Python 绫诲簱鎵ц涓鏉 SQL 鏌ヨ骞跺缁撴灉杩涜涓浜涘鐞嗐
In this example view, we use the MySQLdb library (available at http://www.djangoproject.com/r/python-mysql/) to connect to a MySQL database, retrieve some records, and feed them to a template for display as a Web page:
鍦ㄦ湰渚嬬殑瑙嗗浘涓紝鎴戜滑浣跨敤浜 MySQLdb 绫诲簱锛堝彲浠ヤ粠 http://www.djangoproject.com/r/python-mysql/ 鑾峰緱锛夋潵杩炴帴 MySQL 鏁版嵁搴擄紝鍙栧洖涓浜涜褰曪紝灏嗗畠浠彁渚涚粰妯℃澘浠ユ樉绀轰竴涓綉椤碉細
from django.shortcuts import render_to_response import MySQLdb def book_list(request): db = MySQLdb.connect(user='me', db='mydb', passwd='secret', host='localhost') cursor = db.cursor() cursor.execute('SELECT name FROM books ORDER BY name') names = [row[0] for row in cursor.fetchall()] db.close() return render_to_response('book_list.html', {'names': names})
This approach works, but some problems should jump out at you immediately:
杩欎釜鏂规硶鍙敤锛屼絾寰堝揩涓浜涢棶棰樺皢鍑虹幇鍦ㄤ綘闈㈠墠锛
Were hard-coding the database connection parameters. Ideally, these parameters would be stored in the Django configuration.
鎴戜滑灏嗘暟鎹簱杩炴帴鍙傛暟纭缂栫爜浜庝唬鐮佷箣涓傜悊鎯虫儏鍐典笅锛岃繖浜涘弬鏁板簲褰撲繚瀛樺湪 Django 閰嶇疆涓
Were having to write a fair bit of boilerplate code: creating a connection, creating a cursor, executing a statement, and closing the connection. Ideally, all wed have to do is specify which results we wanted.
鎴戜滑涓嶅緱涓嶉噸澶嶅悓鏍风殑浠g爜锛氬垱寤烘暟鎹簱杩炴帴銆佸垱寤烘暟鎹簱娓告爣銆佹墽琛屾煇涓鍙ャ佺劧鍚庡叧闂暟鎹簱銆傜悊鎯虫儏鍐典笅锛屾垜浠墍闇瑕佸簲璇ュ彧鏄寚瀹氭墍闇鐨勭粨鏋溿
It ties us to MySQL. If, down the road, we switch from MySQL to PostgreSQL, well have to use a different database adapter (e.g., psycopg rather than MySQLdb ), alter the connection parameters, and depending on the nature of the SQL statement possibly rewrite the SQL. Ideally, the database server were using would be abstracted, so that a database server change could be made in a single place.
瀹冩妸鎴戜滑鏍撴鍦 MySQL 涔嬩笂銆傚鏋滆繃娈垫椂闂达紝鎴戜滑瑕佷粠 MySQL 鎹㈠埌 PostgreSQL锛屽氨涓嶅緱涓嶄娇鐢ㄤ笉鍚岀殑鏁版嵁搴撻傞厤鍣紙渚嬪 psycopg 鑰屼笉鏄 MySQLdb 锛夛紝鏀瑰彉杩炴帴鍙傛暟锛屾牴鎹 SQL 璇彞鐨勭被鍨嬪彲鑳借繕瑕佷慨鏀筍QL 銆傜悊鎯虫儏鍐典笅锛屽簲瀵规墍浣跨敤鐨勬暟鎹簱鏈嶅姟鍣ㄨ繘琛屾娊璞★紝杩欐牱涓鏉ュ彧鍦ㄤ竴澶勪慨鏀瑰嵆鍙彉鎹㈡暟鎹簱鏈嶅姟鍣ㄣ
As you might expect, Djangos database layer aims to solve these problems. Heres a sneak preview of how the previous view can be rewritten using Djangos database API:
姝e浣犳墍鏈熷緟鐨勶紝Django鏁版嵁搴撳眰姝f槸鑷村姏浜庤В鍐宠繖浜涢棶棰樸備互涓嬫彁鍓嶆彮绀轰簡濡備綍浣跨敤 Django 鏁版嵁搴 API 閲嶅啓涔嬪墠閭d釜瑙嗗浘銆
from django.shortcuts import render_to_response from mysite.books.models import Book def book_list(request): books = Book.objects.order_by('name') return render_to_response('book_list.html', {'books': books})
Well explain this code a little later in the chapter. For now, just get a feel for how it looks.
鎴戜滑灏嗗湪鏈珷绋嶅悗鐨勫湴鏂硅В閲婅繖娈典唬鐮併傜洰鍓嶈岃█锛屼粎闇瀵瑰畠鏈変釜澶ц嚧鐨勮璇嗐
Before we delve into any more code, lets take a moment to consider the overall design of a database-driven Django Web application.
鍦ㄩ捇鐮旀洿澶氫唬鐮佷箣鍓嶏紝璁╂垜浠厛鑺辩偣鏃堕棿鑰冭檻涓 Django 鏁版嵁椹卞姩 Web 搴旂敤鐨勬讳綋璁捐銆
As we mentioned in previous chapters, Django is designed to encourage loose coupling and strict separation between pieces of an application. If you follow this philosophy, its easy to make changes to one particular piece of the application without affecting the other pieces. In view functions, for instance, we discussed the importance of separating the business logic from the presentation logic by using a template system. With the database layer, were applying that same philosophy to data access logic.
鎴戜滑鍦ㄥ墠闈㈢珷鑺傛彁鍒拌繃锛孌jango 鐨勮璁¢紦鍔辨澗鑰﹀悎鍙婂搴旂敤绋嬪簭涓笉鍚岄儴鍒嗙殑涓ユ牸鍒嗗壊銆傞伒寰繖涓悊蹇电殑璇濓紝瑕佹兂淇敼搴旂敤鐨勬煇閮ㄥ垎鑰屼笉褰卞搷鍏跺畠閮ㄥ垎灏辨瘮杈冨鏄撲簡銆傚湪瑙嗗浘鍑芥暟涓紝鎴戜滑宸茬粡璁ㄨ浜嗛氳繃妯℃澘绯荤粺鎶婁笟鍔¢昏緫鍜岃〃鐜伴昏緫鍒嗛殧寮鐨勯噸瑕佹с傚湪鏁版嵁搴撳眰涓紝鎴戜滑瀵规暟鎹闂昏緫涔熷簲鐢ㄤ簡鍚屾牱鐨勭悊蹇点
Those three pieces together data access logic, business logic, and presentation logic comprise a concept thats sometimes called the Model-View-Controller (MVC) pattern of software architecture. In this pattern, Model refers to the data access layer, View refers to the part of the system that selects what to display and how to display it, and Controller refers to the part of the system that decides which view to use, depending on user input, accessing the model as needed.
鎶婃暟鎹瓨鍙栭昏緫銆佷笟鍔¢昏緫鍜岃〃鐜伴昏緫缁勫悎鍦ㄤ竴璧风殑姒傚康鏈夋椂琚О涓鸿蒋浠舵灦鏋勭殑 Model-View-Controller (MVC)妯″紡銆傚湪杩欎釜妯″紡涓紝 Model 浠h〃鏁版嵁瀛樺彇灞傦紝View 浠h〃鐨勬槸绯荤粺涓夋嫨鏄剧ず浠涔堝拰鎬庝箞鏄剧ず鐨勯儴鍒嗭紝Controller 鎸囩殑鏄郴缁熶腑鏍规嵁鐢ㄦ埛杈撳叆骞惰闇瑕佽闂ā鍨嬶紝浠ュ喅瀹氫娇鐢ㄥ摢涓鍥剧殑閭i儴鍒嗐
Why the Acronym?
涓轰粈涔堢敤缂╁啓锛
The goal of explicitly defining patterns such as MVC is mostly to streamline communication among developers. Instead of having to tell your coworkers, Lets make an abstraction of the data access, then lets have a separate layer that handles data display, and lets put a layer in the middle that regulates this, you can take advantage of a shared vocabulary and say, Lets use the MVC pattern here.
鍍 MVC 杩欐牱鐨勬槑纭畾涔夋ā寮忕殑涓昏鐢ㄤ簬鏀瑰杽寮鍙戜汉鍛樹箣闂寸殑娌熼氥備笌鍏跺憡璇夊悓浜嬶細鈥滆鎴戜滑瀵规暟鎹瓨鍙栬繘琛屾娊璞★紝鐢ㄥ崟鐙竴灞傝礋璐f暟鎹樉绀猴紝鐒跺悗鍦ㄤ腑闂存斁缃竴灞傛潵杩涜鎺у埗鈥濓紝杩樹笉濡傚埄鐢ㄩ氱敤鐨勮瘝姹囧憡璇変粬浠細鈥滆鎴戜滑鍦ㄨ繖閲屼娇鐢 MVC 妯″紡鍚р濄
Django follows this MVC pattern closely enough that it can be called an MVC framework. Heres roughly how the M, V, and C break down in Django:
Django 绱х揣鍦伴伒寰繖绉 MVC 妯″紡锛屽彲浠ョО寰椾笂鏄竴绉 MVC 妗嗘灦銆備互涓嬫槸 Django 涓 M銆乂 鍜 C 鍚勮嚜鐨勫惈涔夛細
M , the data-access portion, is handled by Djangos database layer, which is described in this chapter.
M 锛屾暟鎹瓨鍙栭儴鍒嗭紝鐢眃jango鏁版嵁搴撳眰澶勭悊锛屾湰绔犺璁茶堪鐨勫唴瀹广
V , the portion that selects which data to display and how to display it, is handled by views and templates.
V 锛岄夋嫨鏄剧ず鍝簺鏁版嵁瑕佸強鎬庢牱鏄剧ず鐨勯儴鍒嗭紝鐢辫鍥惧拰妯℃澘澶勭悊銆
C , the portion that delegates to a view depending on user input, is handled by the framework itself by following your URLconf and calling the appropriate Python function for the given URL.
C 锛屾牴鎹敤鎴疯緭鍏ュ娲捐鍥剧殑閮ㄥ垎锛岀敱 Django 妗嗘灦閫氳繃鎸夌収 URLconf 璁剧疆锛屽缁欏畾 URL 璋冪敤鍚堥傜殑 python 鍑芥暟鏉ヨ嚜琛屽鐞嗐
Because the C is handled by the framework itself and most of the excitement in Django happens in models, templates, and views, Django has been referred to as an MTV framework . In the MTV development pattern,
鐢变簬 C 鐢辨鏋惰嚜琛屽鐞嗭紝鑰 Django 閲屾洿鍏虫敞鐨勬槸妯″瀷锛圡odel锛夈佹ā鏉(Template)鍜岃鍥撅紙Views锛夛紝Django 涔熻绉颁负 MTV 妗嗘灦 銆傚湪 MTV 寮鍙戞ā寮忎腑锛
M stands for Model, the data access layer. This layer contains anything and everything about the data: how to access it, how to validate it, which behaviors it has, and the relationships between the data.
M 浠h〃妯″瀷锛圡odel锛夛紝鍗虫暟鎹瓨鍙栧眰銆傝灞傚鐞嗕笌鏁版嵁鐩稿叧鐨勬墍鏈変簨鍔★細濡備綍瀛樺彇銆佸浣曠‘璁ゆ湁鏁堟с佸寘鍚摢浜涜涓轰互鍙婃暟鎹箣闂寸殑鍏崇郴绛夈
T stands for Template, the presentation layer. This layer contains presentation-related decisions: how something should be displayed on a Web page or other type of document.
T 浠h〃妯℃澘(Template)锛屽嵆琛ㄧ幇灞傘傝灞傚鐞嗕笌琛ㄧ幇鐩稿叧鐨勫喅瀹氾細濡備綍鍦ㄩ〉闈㈡垨鍏朵粬绫诲瀷鏂囨。涓繘琛屾樉绀恒
V stands for View, the business logic layer. This layer contains the logic that access the model and defers to the appropriate template(s). You can think of it as the bridge between models and templates.
V 浠h〃瑙嗗浘锛圴iew锛夛紝鍗充笟鍔¢昏緫灞傘傝灞傚寘鍚瓨鍙栨ā鍨嬪強璋冨彇鎭板綋妯℃澘鐨勭浉鍏抽昏緫銆備綘鍙互鎶婂畠鐪嬩綔妯″瀷涓庢ā鏉夸箣闂寸殑妗ユ銆
If youre familiar with other MVC Web-development frameworks, such as Ruby on Rails, you may consider Django views to be the controllers and Django templates to be the views. This is an unfortunate confusion brought about by differing interpretations of MVC. In Djangos interpretation of MVC, the view describes the data that gets presented to the user; its not necessarily just how the data looks, but which data is presented. In contrast, Ruby on Rails and similar frameworks suggest that the controllers job includes deciding which data gets presented to the user, whereas the view is strictly how the data looks, not which data is presented.
濡傛灉浣犵啛鎮夊叾瀹冪殑 MVC Web寮鍙戞鏋讹紝姣旀柟璇 Ruby on Rails锛屼綘鍙兘浼氳涓 Django 瑙嗗浘鏄帶鍒跺櫒锛岃 Django 妯℃澘鏄鍥俱傚緢涓嶅垢锛岃繖鏄 MVC 涓嶅悓璇犻噴鎵寮曡捣鐨勯敊璇璇嗐傚湪 Django 瀵 MVC 鐨勮癄閲婁腑锛岃鍥剧敤鏉ユ弿杩拌灞曠幇缁欑敤鎴风殑鏁版嵁锛涗笉鏄暟鎹湅璧锋潵 鎬庝箞鏍 ,鑰屾槸瑕佸憟鐜 鍝簺 鏁版嵁銆傜浉姣斾箣涓嬶紝Ruby on Rails 鍙婁竴浜涘悓绫绘鏋舵彁鍊℃帶鍒跺櫒璐熻矗鍐冲畾鍚戠敤鎴峰睍鐜板摢浜涙暟鎹紝鑰岃鍥惧垯浠呭喅瀹 濡備綍 灞曠幇鏁版嵁锛岃屼笉鏄睍鐜 鍝簺 鏁版嵁銆
Neither interpretation is more correct than the other. The important thing is to understand the underlying concepts.
涓ょ璇犻噴涓病鏈夊摢涓洿鍔犳纭竴浜涖傞噸瑕佺殑鏄鐞嗚В搴曞眰姒傚康銆
With all of that philosophy in mind, lets start exploring Djangos database layer. First, we need to take care of some initial configuration: we need to tell Django which database server to use and how to connect to it.
璁颁綇杩欎簺鐞嗗康涔嬪悗锛岃鎴戜滑鏉ュ紑濮 Django 鏁版嵁搴撳眰鐨勬帰绱€傞鍏堬紝鎴戜滑闇瑕佹悶瀹氫竴浜涘垵濮嬪寲璁剧疆锛氭垜浠繀椤诲憡璇 Django 瑕佺敤鍝釜鏁版嵁搴撴湇鍔″櫒鍙婂浣曡繛鎺ヤ笂瀹冦
Well assume youve set up a database server, activated it, and created a database within it (e.g., using a CREATE DATABASE statement). SQLite is a special case; in that case, theres no database to create, because SQLite uses standalone files on the filesystem to store its data.
鎴戜滑灏嗗亣瀹氫綘宸茬粡瀹屾垚浜嗘暟鎹簱鏈嶅姟鍣ㄧ殑瀹夎鍜屾縺娲伙紝骞朵笖宸茬粡鍦ㄥ叾涓垱寤轰簡鏁版嵁搴擄紙渚嬪锛岀敤 CREATE DATABASE 璇彞锛夈係QLite 鏁版嵁搴撴湁鐐圭壒鍒紝鐢ㄥ畠鐨勮瘽涓嶉渶瑕佸垱寤烘暟鎹簱锛屽洜涓 SQLite 浣跨敤鏂囦欢绯荤粺涓殑鍗曚釜鏂囦欢鏉ヤ繚瀛樻暟鎹
As with TEMPLATE_DIRS in the previous chapter, database configuration lives in the Django settings file, called settings.py by default. Edit that file and look for the database settings:
璞″墠闈㈢珷鑺傛彁鍒扮殑 TEMPLATE_DIRS 涓鏍凤紝鏁版嵁搴撻厤缃篃鏄湪Django鐨勯厤缃枃浠堕噷锛岀己鐪 鏄 settings.py 銆傜紪杈戞墦寮杩欎釜鏂囦欢骞舵煡鎵炬暟鎹簱閰嶇疆锛
DATABASE_ENGINE = '' DATABASE_NAME = '' DATABASE_USER = '' DATABASE_PASSWORD = '' DATABASE_HOST = '' DATABASE_PORT = ''
Heres a rundown of each setting.
閰嶇疆绾茶濡備笅銆
DATABASE_ENGINE tells Django which database engine to use. If youre using a database with Django, DATABASE_ENGINE must be set to one of the strings shown in Table 5-1.
DATABASE_ENGINE 鍛婅瘔Django浣跨敤鍝釜鏁版嵁搴撳紩鎿庛傚鏋滀綘鍦 Django 涓娇鐢ㄦ暟鎹簱锛 DATABASE_ENGINE 蹇呴』鏄 Table 5-1 涓墍鍒楀嚭鐨勫笺
Table 5-1. Database Engine Settings Setting Database Required Adapter postgresql PostgreSQL psycopg version 1.x, http://www.djangoproject.com/r/python-pgsql/1/. postgresql_psycopg2 PostgreSQL psycopg version 2.x, http://www.djangoproject.com/r/python-pgsql/. mysql MySQL MySQLdb , http://www.djangoproject.com/r/python-mysql/. sqlite3 SQLite No adapter needed if using Python 2.5+. Otherwise, pysqlite , http://www.djangoproject.com/r/python-sqlite/. ado_mssql Microsoft SQL Server adodbapi version 2.0.1+, http://www.djangoproject.com/r/python-ado/. oracle Oracle cx_Oracle , http://www.djangoproject.com/r/python-oracle/.
琛 5-1. 鏁版嵁搴撳紩鎿庤缃 璁剧疆 鏁版嵁搴 閫傞厤鍣 postgresql PostgreSQL psycopg 鐗堟湰 1.x, http://www.djangoproject.com/r/python-pgsql/1/. postgresql_psycopg2 PostgreSQL psycopg 鐗堟湰 2.x, http://www.djangoproject.com/r/python-pgsql/. mysql MySQL MySQLdb , http://www.djangoproject.com/r/python-mysql/. sqlite3 SQLite Python 2.5+ 鍐呭缓銆 鍏朵粬, pysqlite , http://www.djangoproject.com/r/python-sqlite/. ado_mssql Microsoft SQL Server adodbapi 鐗堟湰 2.0.1+, http://www.djangoproject.com/r/python-ado/. oracle Oracle cx_Oracle , http://www.djangoproject.com/r/python-oracle/. Note that for whichever database back-end you use, youll need to download and install the appropriate database adapter. Each one is available for free on the Web; just follow the links in the Required Adapter column in Table 5-1.
瑕佹敞鎰忕殑鏄棤璁洪夋嫨浣跨敤鍝釜鏁版嵁搴撴湇鍔″櫒锛岄兘蹇呴』涓嬭浇鍜屽畨瑁呭搴旂殑鏁版嵁搴撻傞厤鍣ㄣ傝闂〃 5-1 涓滄墍闇閫傞厤鍣ㄢ濅竴鏍忎腑鐨勯摼鎺ワ紝鍙氳繃浜掕仈缃戝厤璐硅幏鍙栬繖浜涢傞厤鍣ㄣ
DATABASE_NAME tells Django the name of your database. If youre using SQLite, specify the full filesystem path to the database file on your filesystem (e.g., '/home/django/mydata.db' ).
DATABASE_NAME 灏嗘暟鎹簱鍚嶇О鍛婄煡 Django 銆傚鏋滀娇鐢 SQLite锛岃瀵规暟鎹簱鏂囦欢鎸囧畾瀹屾暣鐨勬枃浠剁郴缁熻矾寰勩傦紙渚嬪 '/home/django/mydata.db' 锛夈
DATABASE_USER tells Django which username to use when connecting to your database. If youre using SQLite, leave this blank.
DATABASE_USER 鍛婅瘔 Django 鐢ㄥ摢涓敤鎴疯繛鎺ユ暟鎹簱銆傚鏋滅敤SQLite锛岀┖鐧藉嵆鍙
DATABASE_PASSWORD tells Django which password to use when connecting to your database. If youre using SQLite or have an empty password, leave this blank.
DATABASE_PASSWORD 鍛婅瘔Django杩炴帴鐢ㄦ埛鐨勫瘑鐮併係QLite 鐢ㄧ┖瀵嗙爜鍗冲彲銆
DATABASE_HOST tells Django which host to use when connecting to your database. If your database is on the same computer as your Django installation (i.e., localhost), leave this blank. If youre using SQLite, leave this blank.
DATABASE_HOST 鍛婅瘔 Django 杩炴帴鍝竴鍙颁富鏈虹殑鏁版嵁搴撴湇鍔″櫒銆傚鏋滄暟鎹簱涓 Django 瀹夎浜庡悓涓鍙拌绠楁満锛堝嵆鏈満锛夛紝鍙皢姝ら」淇濈暀绌虹櫧銆備娇鐢 SQLite 锛屼篃鍙繚鐣欑┖鐧姐
MySQL is a special case here. If this value starts with a forward slash ('/' ) and youre using MySQL, MySQL will connect via a Unix socket to the specified socket, for example:
姝ゅ鐨 MySQL 鏄竴涓壒渚嬨傚鏋滀娇鐢ㄧ殑鏄 MySQL 涓旇椤硅缃肩敱鏂滄潬锛 '/' 锛夊紑澶达紝MySQL 灏嗛氳繃 Unix socket 鏉ヨ繛鎺ユ寚瀹氱殑濂楁帴瀛楋紝渚嬪锛
DATABASE_HOST = '/var/run/mysql'
If youre using MySQL and this value doesnt start with a forward slash, then this value is assumed to be the host.
濡傛灉鐢 MySQL 鑰岃椤硅缃殑鍊 涓嶆槸 浠ユ鏂滅嚎寮濮嬬殑锛岀郴缁熷皢鍋囧畾璇ラ」鍊兼槸涓绘満鍚嶃
DATABASE_PORT tells Django which port to use when connecting to your database. If youre using SQLite, leave this blank. Otherwise, if you leave this blank, the underlying database adapter will use whichever port is default for your given database server. In most cases, the default port is fine, so you can leave this blank.
DATABASE_PORT 鍛婅瘔 Django 杩炴帴鏁版嵁搴撴椂浣跨敤鍝釜绔彛銆傚鏋滅敤SQLite锛岀┖鐧藉嵆鍙傚叾浠栨儏鍐典笅锛屽鏋滃皢璇ラ」璁剧疆淇濈暀绌虹櫧锛屽簳灞傛暟鎹簱閫傞厤鍣ㄥ皢浼氳繛鎺ユ墍缁欏畾鏁版嵁搴撴湇鍔″櫒鐨勭己鐪佺鍙c傚湪澶氭暟鎯呭喌涓嬶紝浣跨敤缂虹渷绔彛灏卞彲浠ヤ簡锛屽洜姝や綘鍙互灏嗚椤硅缃繚鐣欑┖鐧姐
Once youve entered those settings, test your configuration. First, from within the mysite project directory you created in Chapter 2, run the command python manage.py shell .
杈撳叆瀹岃缃悗锛屾祴璇曚竴涓嬮厤缃儏鍐点傞鍏堬紝杞埌鍦ㄧ浜岀珷鍒涘缓鐨 mysite 椤圭洰鐩綍锛岃繍琛 python manage.py shell 鍛戒护銆
Youll notice this starts a Python interactive interpreter. Looks can be deceiving, though! Theres an important difference between running the command python manage.py shell within your Django project directory and the more generic python . The latter is the basic Python shell, but the former tells Django which settings file to use before it starts the shell. This is a key requirement for doing database queries: Django needs to know which settings file to use in order to get your database connection information.
浣犱細鐪嬪埌璇ュ懡浠ゅ惎鍔ㄤ簡涓涓 Python 浜や簰鐣岄潰銆傝繍琛屽懡浠 python manage.py shell 鍚姩鐨勪氦浜掔晫闈㈠拰 鏍囧噯鐨 python 浜や簰鐣岄潰鏈夊緢澶х殑鍖哄埆銆傜湅璧锋潵閮芥槸鍩烘湰鐨刾ython澶栧3锛坰hell锛夛紝 浣嗘槸鍓嶈呭憡璇塂jango浣跨敤鍝釜閰嶇疆鏂囦欢鍚姩銆傝繖瀵规暟鎹簱鎿嶄綔鏉ヨ寰堝叧閿細Django闇瑕 鐭ラ亾浣跨敤鍝釜閰嶇疆鏂囦欢鏉ヨ幏寰楁暟鎹簱杩炴帴淇℃伅銆
Behind the scenes, python manage.py shell simply assumes that your settings file is in the same directory as manage.py . There are other ways to tell Django which settings module to use, but these subtleties will be covered later. For now, use python manage.py shell whenever you need to drop into the Python interpreter to do Django-specific tinkering.
python manage.py shell 鍋囧畾浣犵殑閰嶇疆鏂囦欢灏卞湪鍜 manage.py 涓鏍风殑鐩綍涓 浠ュ悗灏嗕細璁插埌浣跨敤鍏朵粬鐨勬柟寮忔潵鍛婅瘔Django浣跨敤鍏朵粬鐨勯厤缃枃浠躲
Once youve entered the shell, type these commands to test your database configuration:
杈撳叆涓嬮潰杩欎簺鍛戒护鏉ユ祴璇曚綘鐨勬暟鎹簱閰嶇疆锛
>>> from django.db import connection >>> cursor = connection.cursor()
If nothing happens, then your database is configured properly. Otherwise, check the error message for clues about whats wrong. Table 5-2 shows some common errors.
濡傛灉娌℃湁鏄剧ず浠涔堥敊璇俊鎭紝閭d箞浣犵殑鏁版嵁搴撻厤缃槸姝g‘鐨勩傚惁鍒欙紝浣犲氨寰 鏌ョ湅閿欒淇℃伅鏉ョ籂姝i敊璇傝〃 5-2 鏄竴浜涘父瑙侀敊璇
Error Message | Solution |
---|---|
You havent set the DATABASE_ENGINE setting yet. | Set the DATABASE_ENGINE setting to something other than an empty string. |
Environment variable DJANGO_SETTINGS_MODULE is undefined. | Run the command python manage.py shell rather than python . |
Error loading _____ module: No module named _____. | You havent installed the appropriate database-specific adapter (e.g., psycopg or MySQLdb ). |
_____ isnt an available database backend. | Set your DATABASE_ENGINE setting to one of the valid engine settings described previously. Perhaps you made a typo? |
database _____ does not exist | Change the DATABASE_NAME setting to point to a database that exists, or execute the appropriate CREATE DATABASE statement in order to create it. |
role _____ does not exist | Change the DATABASE_USER setting to point to a user that exists, or create the user in your database. |
could not connect to server | Make sure DATABASE_HOST and DATABASE_PORT are set correctly, and make sure the server is running. |
閿欒淇℃伅 | 瑙e喅鏂规 |
---|---|
You havent set the DATABASE_ENGINE setting yet. | 璁剧疆姝g‘鐨 DATABASE_ENGINE 閰嶇疆 |
Environment variable DJANGO_SETTINGS_MODULE is undefined. | 杩愯鍛戒护琛 python manage.py shell 鑰屼笉鏄 python . |
Error loading _____ module: No module named _____. | 浣犳病鏈夊畨瑁呯浉鍏崇殑鏁版嵁搴撻傞厤鍣 (渚嬪, psycopg 鎴 MySQLdb ). |
_____ isnt an available database backend. | 璁剧疆姝g‘鐨 DATABASE_ENGINE 閰嶇疆 涔熻鏄嫾鍐欓敊璇紵 |
database _____ does not exist | 璁剧疆 DATABASE_NAME 閰嶇疆鍒颁竴涓凡鏈夌殑鏁版嵁搴擄紝 鎴栬呬娇鐢 CREATE DATABASE 璇彞鍒涘缓鏁版嵁搴撱 |
role _____ does not exist | 淇敼 DATABASE_USER 閰嶇疆鍒颁竴涓湁鏁堢敤鎴 |
could not connect to server | 纭 DATABASE_HOST 鍜 DATABASE_PORT 璁剧疆鏄纭殑锛屽苟 纭鏈嶅姟鍣ㄦ槸鍦ㄨ繍琛岀殑銆 |
Now that youve verified the connection is working, its time to create a Django app a bundle of Django code, including models and views, that lives together in a single Python package and represents a full Django application.
浣犵幇鍦ㄥ凡缁忕‘璁ゆ暟鎹簱杩炴帴姝e父宸ヤ綔浜嗭紝璁╂垜浠潵鍒涘缓涓涓 Django app 锛屽紑濮嬬紪鐮佹ā鍨嬪拰瑙嗗浘銆傝繖浜涙枃浠舵斁缃湪鍚屼竴涓寘涓苟涓斿舰鎴愪负涓涓畬鏁寸殑Django搴旂敤绋嬪簭銆
Its worth explaining the terminology here, because this tends to trip up beginners. Wed already created a project , in Chapter 2, so whats the difference between a project and an app ? The difference is that of configuration vs. code:
鍦ㄨ繖閲岃鍏堣В閲婁竴浜涙湳璇紝鍒濆鑰呭彲鑳戒細娣锋穯瀹冧滑銆傚湪绗簩绔犳垜浠凡缁忓垱寤轰簡 project , 閭d箞 project 鍜 app 涔嬮棿鍒板簳鏈変粈涔堜笉鍚屽憿锛 瀹冧滑鐨勫尯鍒氨鏄竴涓槸閰嶇疆鍙︿竴涓槸浠g爜锛
A project is an instance of a certain set of Django apps, plus the configuration for those apps.
涓涓猵roject鍖呭惈寰堝涓狣jango app浠ュ強瀵瑰畠浠殑閰嶇疆銆
Technically, the only requirement of a project is that it supplies a settings file, which defines the database connection information, the list of installed apps, the TEMPLATE_DIRS , and so forth.
鎶鏈笂锛宲roject鐨勪綔鐢ㄦ槸鎻愪緵閰嶇疆鏂囦欢锛屾瘮鏂硅鍝噷瀹氫箟鏁版嵁搴撹繛鎺ヤ俊鎭, 瀹夎鐨刟pp鍒楄〃锛 TEMPLATE_DIRS 锛岀瓑绛夈
An app is a portable set of Django functionality, usually including models and views, that lives together in a single Python package.
涓涓猘pp鏄竴濂桪jango鍔熻兘鐨勯泦鍚堬紝閫氬父鍖呮嫭妯″瀷鍜岃鍥撅紝鎸塒ython鐨勫寘缁撴瀯鐨勬柟寮忓瓨鍦ㄣ
For example, Django comes with a number of apps, such as a commenting system and an automatic admin interface. A key thing to note about these apps is that theyre portable and reusable across multiple projects.
渚嬪锛孌jango鏈韩鍐呭缓鏈変竴浜沘pp锛屼緥濡傛敞閲婄郴缁熷拰鑷姩绠$悊鐣岄潰銆 app鐨勪竴涓叧閿偣鏄畠浠槸寰堝鏄撶Щ妞嶅埌鍏朵粬project鍜岃澶氫釜project閲嶇敤銆
There are very few hard-and-fast rules about how you fit your Django code into this scheme; its flexible. If youre building a simple Web site, you may use only a single app. If youre building a complex Web site with several unrelated pieces such as an e-commerce system and a message board, youll probably want to split those into separate apps so that youll be able to reuse them individually in the future.
濡傛灉浣犲彧鏄缓閫犱竴涓畝鍗曠殑web绔欑偣锛岄偅涔堝彲鑳戒綘鍙渶瑕佷竴涓猘pp灏卞彲浠ヤ簡銆傚鏋滄槸澶嶆潅鐨勮薄 鐢靛瓙鍟嗗姟涔嬬被鐨刉eb绔欑偣锛屼綘鍙兘闇瑕佹妸杩欎簺鍔熻兘鍒掑垎鎴愪笉鍚岀殑app锛屼互渚夸互鍚庨噸鐢ㄣ
Indeed, you dont necessarily need to create apps at all, as evidenced by the example view functions weve created so far in this book. In those cases, we simply created a file called views.py , filled it with view functions, and pointed our URLconf at those functions. No apps were needed.
纭疄锛屼綘杩樺彲浠ヤ笉鐢ㄥ垱寤篴pp锛屼緥濡備互鍓嶅啓鐨勮鍥撅紝鍙槸绠鍗曠殑鏀惧湪 views.py 锛屼笉闇瑕乤pp銆
However, theres one requirement regarding the app convention: if youre using Djangos database layer (models), you must create a Django app. Models must live within apps. Thus, in order to start writing our models, well need to create a new app.
褰撶劧锛岀郴缁熷app鏈変竴涓害瀹氾細濡傛灉浣犱娇鐢ㄤ簡Django鐨勬暟鎹簱灞傦紙妯″瀷锛夛紝浣 蹇呴』鍒涘缓涓涓猟jango app銆傛ā鍨嬪繀椤诲湪杩欎釜app涓瓨鍦ㄣ傚洜姝わ紝涓轰簡寮濮嬪缓閫 鎴戜滑鐨勬ā鍨嬶紝鎴戜滑蹇呴』鍒涘缓涓涓柊鐨刟pp銆
Within the mysite project directory you created in Chapter 2, type this command to create a new app named books:
杞埌 mysite 椤圭洰鐩綍锛屾墽琛屼笅闈㈢殑鍛戒护鏉ュ垱寤轰竴涓柊app鍙仛books锛
python manage.py startapp books
This command does not produce any output, but it does create a books directory within the mysite directory. Lets look at the contents of that directory:
杩欎釜鍛戒护娌℃湁杈撳嚭浠涔堬紝瀹冨湪 mysite 鐨勭洰褰曢噷鍒涘缓浜嗕竴涓 books 鐩綍銆 璁╂垜浠潵鐪嬬湅杩欎釜鐩綍鐨勫唴瀹癸細
books/ __init__.py models.py views.py
These files will contain the models and views for this app.
杩欎簺鏂囦欢閲岄潰灏卞寘鍚簡杩欎釜app鐨勬ā鍨嬪拰瑙嗗浘銆
Have a look at models.py and views.py in your favorite text editor. Both files are empty, except for an import in models.py . This is the blank slate for your Django app.
鐪嬩竴涓 models.py 鍜 views.py 鏂囦欢銆傚畠浠兘鏄┖鐨勶紝闄や簡 models.py 閲屾湁涓涓 import銆
As we discussed earlier in this chapter, the M in MTV stands for Model. A Django model is a description of the data in your database, represented as Python code. Its your data layout the equivalent of your SQL CREATE TABLE statements except its in Python instead of SQL, and it includes more than just database column definitions. Django uses a model to execute SQL code behind the scenes and return convenient Python data structures representing the rows in your database tables. Django also uses models to represent higher-level concepts that SQL cant necessarily handle.
鎴戜滑鏃╀簺鏃跺欒皥鍒般侻TV閲岀殑M浠h〃妯″瀷銆侱jango妯″瀷鏄敤Python浠g爜褰㈠紡琛ㄨ堪鐨勬暟鎹湪鏁版嵁搴 涓殑瀹氫箟銆傚鏁版嵁灞傛潵璇村畠绛夊悓浜 CREATE TABLE 璇彞锛屽彧涓嶈繃鎵ц鐨勬槸Python浠g爜鑰屼笉鏄 SQL锛岃屼笖杩樺寘鍚簡姣旀暟鎹簱瀛楁瀹氫箟鏇村鐨勫惈涔夈侱jango鐢ㄦā鍨嬪湪鍚庡彴鎵цSQL浠g爜骞舵妸缁撴灉 鐢≒ython鐨勬暟鎹粨鏋勬潵鎻忚堪锛岃繖鏍蜂綘鍙互寰堟柟渚跨殑浣跨敤杩欎簺鏁版嵁銆侱jango杩樼敤妯″瀷鏉ユ弿杩癝QL涓嶈兘 澶勭悊鐨勯珮绾ф蹇点
If youre familiar with databases, your immediate thought might be, Isnt it redundant to define data models in Python and in SQL? Django works the way it does for several reasons:
濡傛灉浣犲鏁版嵁搴撳緢鐔熸倝锛屼綘鍙兘椹笂灏变細鎯冲埌锛岀敤Python 鍜 SQL鏉ュ畾涔夋暟鎹ā鍨嬫槸涓嶆槸鏈夌偣澶氫綑锛 Django杩欐牱鍋氭槸鏈変笅闈㈠嚑涓師鍥犵殑锛
Introspection requires overhead and is imperfect. In order to provide convenient data-access APIs, Django needs to know the database layout somehow , and there are two ways of accomplishing this. The first way would be to explicitly describe the data in Python, and the second way would be to introspect the database at runtime to determine the data models.
鑷渷锛堣繍琛屾椂鑷姩璇嗗埆鏁版嵁搴擄級浼氬鑷磋繃杞藉拰鏈夋暟鎹畬鏁存ч棶棰樸備负浜嗘彁渚涙柟渚跨殑鏁版嵁璁块棶API锛 Django闇瑕佷互 鏌愮鏂瑰紡 鐭ラ亾鏁版嵁搴撳眰鍐呴儴淇℃伅锛屾湁涓ょ瀹炵幇鏂瑰紡銆 绗竴绉嶆柟寮忔槸鐢≒ython鏄庣‘鐨勫畾涔夋暟鎹ā鍨嬶紝绗簩绉嶆柟寮忔槸閫氳繃杩愯鏃舵壂鎻忔暟鎹簱鏉ヨ嚜鍔ㄤ睛娴嬭瘑鍒暟鎹ā鍨嬨
This second way seems cleaner, because the metadata about your tables lives in only one place, but it introduces a few problems. First, introspecting a database at runtime obviously requires overhead. If the framework had to introspect the database each time it processed a request, or even when the Web server was initialized, this would incur an unacceptable level of overhead. (While some believe that level of overhead is acceptable, Djangos developers aim to trim as much framework overhead as possible, and this approach has succeeded in making Django faster than its high-level framework competitors in benchmarks.) Second, some databases, notably older versions of MySQL, do not store sufficient metadata for accurate and complete introspection.
绗簩绉嶆柟寮忕湅璧锋潵鏇存竻鏅帮紝鍥犱负鏁版嵁琛ㄤ俊鎭彧瀛樻斁鍦ㄤ竴涓湴鏂-鏁版嵁搴撻噷锛屼絾鏄細甯︽潵涓浜涢棶棰樸 棣栧厛锛岃繍琛屾椂鎵弿鏁版嵁搴撲細甯︽潵涓ラ噸鐨勭郴缁熻繃杞姐傚鏋滄瘡涓姹傞兘瑕佹壂鎻忔暟鎹簱鐨勮〃缁撴瀯锛屾垨鑰呭嵆渚挎槸 鏈嶅姟鍚姩鏃跺仛涓娆¢兘鏄細甯︽潵涓嶈兘鎺ュ彈鐨勭郴缁熻繃杞姐傦紙Django灏藉姏閬垮厤杩囪浇锛岃屼笖鎴愬姛鍋氬埌浜嗚繖涓鐐癸級 鍏舵锛屾湁浜涙暟鎹簱锛屼緥濡傝佺増鏈殑MySQL锛屾病鏈夋彁渚涜冻澶熺殑鍏冩暟鎹潵瀹屾暣鍦伴噸鏋勬暟鎹〃銆
Writing Python is fun, and keeping everything in Python limits the number of times your brain has to do a context switch. It helps productivity if you keep yourself in a single programming environment/mentality for as long as possible. Having to write SQL, then Python, and then SQL again is disruptive.
缂栧啓Python浠g爜鏄潪甯告湁瓒g殑锛屼繚鎸佺敤Python鐨勬柟寮忔濊冧細閬垮厤浣犵殑澶ц剳鍦ㄤ笉鍚岄鍩熸潵鍥炲垏鎹€ 杩欏彲浠ュ府鍔╀綘鎻愰珮鐢熶骇鐜囥備笉寰椾笉鍘婚噸澶嶅啓SQL锛屽啀鍐橮ython浠g爜锛屽啀鍐橲QL锛…锛屼細璁╀綘澶撮兘瑕佽浜嗐
Having data models stored as code rather than in your database makes it easier to keep your models under version control. This way, you can easily keep track of changes to your data layouts.
鎶婃暟鎹ā鍨嬬敤浠g爜鐨勬柟寮忚〃杩版潵璁╀綘鍙互瀹规槗瀵瑰畠浠繘琛岀増鏈帶鍒躲傝繖鏍凤紝浣犲彲浠ュ緢瀹规槗浜嗚В鏁版嵁灞 鐨勫彉鍔ㄦ儏鍐点
SQL allows for only a certain level of metadata about a data layout. Most database systems, for example, do not provide a specialized data type for representing email addresses or URLs. Django models do. The advantage of higher-level data types is higher productivity and more reusable code.
SQL鍙兘鎻忚堪鐗瑰畾绫诲瀷鐨勬暟鎹瓧娈点備緥濡傦紝澶у鏁版暟鎹簱閮芥病鏈夋暟鎹瓧娈电被鍨嬫弿杩癊mail鍦板潃銆乁RL銆 鑰岀敤Django鐨勬ā鍨嬪彲浠ュ仛鍒拌繖涓鐐广傚ソ澶勫氨鏄珮绾х殑鏁版嵁绫诲瀷甯︽潵楂樼敓浜у姏鍜屾洿濂界殑浠g爜閲嶇敤銆
SQL is inconsistent across database platforms. If youre distributing a Web application, for example, its much more pragmatic to distribute a Python module that describes your data layout than separate sets of CREATE TABLE statements for MySQL, PostgreSQL, and SQLite.
SQL杩樻湁鍦ㄤ笉鍚屾暟鎹簱骞冲彴鐨勫吋瀹规ч棶棰樸備綘蹇呴』涓轰笉鍚岀殑鏁版嵁搴撶紪鍐欎笉鍚岀殑SQL鑴氭湰锛 鑰孭ython鐨勬ā鍧楀氨涓嶄細鏈夎繖涓棶棰樸
A drawback of this approach, however, is that its possible for the Python code to get out of sync with whats actually in the database. If you make changes to a Django model, youll need to make the same changes inside your database to keep your database consistent with the model. Well detail some strategies for handling this problem later in this chapter.
褰撶劧锛岃繖涓柟娉曚篃鏈変竴涓己鐐癸紝灏辨槸Python浠g爜鍜屾暟鎹簱琛ㄧ殑鍚屾闂銆傚鏋滀綘淇敼浜嗕竴涓狣jango妯″瀷锛 浣犺鑷繁鍋氬伐浣滄潵淇濊瘉鏁版嵁搴撳拰妯″瀷鍚屾銆傛垜浠皢鍦ㄧ◢鍚庤瑙hВ鍐宠繖涓棶棰樼殑鍑犵绛栫暐銆
Finally, we should note that Django includes a utility that can generate models by introspecting an existing database. This is useful for quickly getting up and running with legacy data.
鏈鍚,鎴戜滑瑕佹彁閱掍綘Django鎻愪緵浜嗗疄鐢ㄥ伐鍏锋潵浠庣幇鏈夌殑鏁版嵁搴撹〃涓嚜鍔ㄦ壂鎻忕敓鎴愭ā鍨嬨 杩欏宸叉湁鐨勬暟鎹簱鏉ヨ鏄潪甯稿揩鎹锋湁鐢ㄧ殑銆
As an ongoing example in this chapter and the next chapter, well focus on a basic book/author/publisher data layout. We use this as our example because the conceptual relationships between books, authors, and publishers are well known, and this is a common data layout used in introductory SQL textbooks. Youre also reading a book that was written by authors and produced by a publisher!
鍦ㄦ湰绔犲拰鍚庣画绔犺妭閲岋紝鎴戜滑灏嗛泦涓埌涓涓熀鏈殑 涔︾睄/浣滆/鍑虹増鍟 鏁版嵁灞備笂銆傛垜浠繖鏍峰仛鏄洜涓 杩欐槸涓涓紬鎵鍛ㄧ煡鐨勪緥瀛愶紝寰堝SQL鏈夊叧鐨勪功绫嶄篃甯哥敤杩欎釜涓句緥銆備綘鐜板湪鐪嬬殑杩欐湰涔︿篃鏄敱浣滆 鍒涗綔鍐嶇敱鍑虹増鍟嗗嚭鐗堢殑鍝︼紒
Well suppose the following concepts, fields, and relationships:
鎴戜滑鏉ュ亣瀹氫笅闈㈢殑杩欎簺姒傚康銆佸瓧娈靛拰鍏崇郴锛
An author has a salutation (e.g., Mr. or Mrs.), a first name, a last name, an email address, and a headshot photo.
浣滆呮湁灏婄О锛堜緥濡傦紝鍏堢敓鎴栬呭コ澹級锛屽锛屽悕锛岃繕鏈塃mail鍦板潃锛屽ご鍍忋
A publisher has a name, a street address, a city, a state/province, a country, and a Web site.
鍑虹増鍟嗘湁鍚嶇О锛屽湴鍧锛屾墍鍦ㄥ煄甯傘佺渷锛屽浗瀹讹紝缃戠珯銆
A book has a title and a publication date. It also has one or more authors (a many-to-many relationship with authors) and a single publisher (a one-to-many relationship aka foreign key to publishers).
涔︾睄鏈変功鍚嶅拰鍑虹増鏃ユ湡銆傚畠鏈変竴涓垨澶氫釜浣滆咃紙鍜屼綔鑰呮槸澶氬澶氱殑鍏宠仈鍏崇郴[many-to-many]锛夛紝 鍙湁涓涓嚭鐗堝晢锛堝拰鍑虹増鍟嗘槸涓瀵瑰鐨勫叧鑱斿叧绯籟one-to-many]锛屼篃琚О浣滃閿甗foreign key]锛
The first step in using this database layout with Django is to express it as Python code. In the models.py file that was created by the startapp command, enter the following:
绗竴姝ユ槸鐢≒ython浠g爜鏉ユ弿杩板畠浠傛墦寮 models.py 骞惰緭鍏ヤ笅闈㈢殑鍐呭锛
from django.db import models class Publisher(models.Model): name = models.CharField(maxlength=30) address = models.CharField(maxlength=50) city = models.CharField(maxlength=60) state_province = models.CharField(maxlength=30) country = models.CharField(maxlength=50) website = models.URLField() class Author(models.Model): salutation = models.CharField(maxlength=10) first_name = models.CharField(maxlength=30) last_name = models.CharField(maxlength=40) email = models.EmailField() headshot = models.ImageField(upload_to='/tmp') class Book(models.Model): title = models.CharField(maxlength=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField()
Lets quickly examine this code to cover the basics. The first thing to notice is that each model is represented by a Python class that is a subclass of django.db.models.Model . The parent class, Model , contains all the machinery necessary to make these objects capable of interacting with a database and that leaves our models responsible solely for defining their fields, in a nice and compact syntax. Believe it or not, this is all the code we need to write to have basic data access with Django.
璁╂垜浠潵蹇熻瑙d竴涓嬭繖浜涗唬鐮佺殑鍚箟銆傞鍏堣娉ㄦ剰鐨勪簨鏄瘡涓暟鎹ā鍨嬮兘鏄 django.db.models.Model 鐨勫瓙绫汇傚畠鐨勭埗绫 Model 鍖呭惈浜嗘墍鏈夊拰鏁版嵁搴 鎵撲氦閬撶殑鏂规硶锛屽苟鎻愪緵浜嗕竴涓畝娲佹紓浜殑瀹氫箟璇硶銆備笉绠′綘鐩镐俊杩樻槸涓嶇浉淇★紝 杩欏氨鏄垜浠敤Django鍐欑殑鏁版嵁鍩烘湰瀛樺彇鍔熻兘鐨勫叏閮ㄤ唬鐮併
Each model generally corresponds to a single database table, and each attribute on a model generally corresponds to a column in that database table. The attribute name corresponds to the columns name, and the type of field (e.g., CharField ) corresponds to the database column type (e.g., varchar ). For example, the Publisher model is equivalent to the following table (assuming PostgreSQL CREATE TABLE syntax):
姣忎釜妯″瀷鐩稿綋浜庡崟涓暟鎹簱琛紝姣忎釜灞炴т篃鏄繖涓〃涓殑涓涓瓧娈点 灞炴у悕灏辨槸瀛楁鍚嶏紝瀹冪殑绫诲瀷锛堜緥濡 CharField 锛夌浉褰撲簬鏁版嵁搴撶殑瀛楁绫诲瀷 锛堜緥濡 varchar 锛夈備緥濡傦紝 Publisher 妯″潡绛夊悓浜庝笅闈㈣繖寮犺〃锛堢敤Postgresql 鐨 CREATE TABLE 璇硶鎻忚堪锛夛細
CREATE TABLE "books_publisher" ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(30) NOT NULL, "address" varchar(50) NOT NULL, "city" varchar(60) NOT NULL, "state_province" varchar(30) NOT NULL, "country" varchar(50) NOT NULL, "website" varchar(200) NOT NULL );
Indeed, Django can generate that CREATE TABLE statement automatically, as well show in a moment.
浜嬪疄涓婏紝姝e杩囦竴浼氬効鎴戜滑鎵瑕佸睍绀虹殑锛孌jango 鍙互鑷姩鐢熸垚杩欎簺 CREATE TABLE 璇彞銆
The exception to the one-class-per-database-table rule is the case of many-to-many relationships. In our example models, Book has a ManyToManyField called authors . This designates that a book has one or many authors, but the Book database table doesnt get an authors column. Rather, Django creates an additional table a many-to-many join table that handles the mapping of books to authors.
鈥滄瘡涓暟鎹簱琛ㄥ搴斾竴涓被鈥濊繖鏉¤鍒欑殑渚嬪鎯呭喌鏄瀵瑰鍏崇郴銆傚湪鎴戜滑鐨勮寖渚嬫ā鍨嬩腑锛 Book 鏈変竴涓 澶氬澶氬瓧娈 鍙仛 authors 銆 璇ュ瓧娈佃〃鏄庝竴鏈功绫嶆湁涓涓垨澶氫釜浣滆咃紝浣 Book 鏁版嵁搴撹〃鍗村苟娌℃湁 authors 瀛楁銆傜浉鍙嶏紝Django鍒涘缓浜嗕竴涓澶栫殑琛紙澶氬澶氳繛鎺ヨ〃锛夋潵澶勭悊涔︾睄鍜屼綔鑰呬箣闂寸殑鏄犲皠鍏崇郴銆
For a full list of field types and model syntax options, see Appendix B.
璇锋煡鐪嬮檮褰 B 浜嗚В鎵鏈夌殑瀛楁绫诲瀷鍜屾ā鍨嬭娉曢夐」銆
Finally, note we havent explicitly defined a primary key in any of these models. Unless you instruct it otherwise, Django automatically gives every model an integer primary key field called id . Each Django model is required to have a single-column primary key.
鏈鍚庨渶瑕佹敞鎰忕殑鏄細鎴戜滑骞舵病鏈夋樉寮忓湴涓鸿繖浜涙ā鍨嬪畾涔変换浣曚富閿傞櫎闈炰綘鎸囧畾锛屽惁鍒 Django 浼氳嚜鍔ㄤ负姣忎釜妯″瀷鍒涘缓涓涓彨鍋 id 鐨勪富閿傛瘡涓 Django 妯″瀷蹇呴』瑕佹湁涓涓崟鍒椾富閿
Weve written the code; now lets create the tables in our database. In order to do that, the first step is to activate these models in our Django project. We do that by adding the books app to the list of installed apps in the settings file.
瀹屾垚杩欎簺浠g爜涔嬪悗锛岀幇鍦ㄨ鎴戜滑鏉ュ湪鏁版嵁搴撲腑鍒涘缓杩欎簺琛ㄣ傝瀹屾垚璇ラ」宸ヤ綔锛岀涓姝ユ槸鍦 Django 椤圭洰涓 婵娲 杩欎簺妯″瀷銆傚皢 books app 娣诲姞鍒伴厤缃枃浠剁殑宸 installed apps 鍒楄〃涓嵆鍙畬鎴愭姝ラ銆
Edit the settings.py file again, and look for the INSTALLED_APPS setting. INSTALLED_APPS tells Django which apps are activated for a given project. By default, it looks something like this:
鍐嶆缂栬緫 settings.py 鏂囦欢锛 鎵惧埌 INSTALLED_APPS 璁剧疆銆 INSTALLED_APPS 鍛婅瘔 Django 椤圭洰鍝簺 app 澶勪簬婵娲荤姸鎬併傜己鐪佹儏鍐典笅濡備笅鎵绀猴細
INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', )
Temporarily comment out all four of those strings by putting a hash character (# ) in front of them. (Theyre included by default as a common-case convenience, but well activate and discuss them later.) While youre at it, modify the default MIDDLEWARE_CLASSES and TEMPLATE_CONTEXT_PROCESSORS settings. These depend on some of the apps we just commented out. Then, add 'mysite.books' to the INSTALLED_APPS list, so the setting ends up looking like this:
鎶婅繖鍥涗釜璁剧疆鍓嶉潰鍔#涓存椂娉ㄩ噴璧锋潵銆傦紙瀹冧滑鏄竴浜涚己鐪佺殑鍏敤璁剧疆锛岀幇鍦ㄥ厛涓嶇 瀹冧滑锛屼互鍚庡啀鏉ヨ璁猴級鍚屾牱鐨勶紝淇敼缂虹渷鐨 MIDDLEWARE_CLASSES 鍜 TEMPLATE_CONTEXT_PROCESSORS 璁剧疆锛岄兘娉ㄩ噴璧锋潵銆 鐒跺悗娣诲姞 'mysite.books' 鍒 INSTALLED_APPS 鍒楄〃锛岀幇鍦ㄧ湅璧锋潵鏄繖鏍凤細
MIDDLEWARE_CLASSES = ( # 'django.middleware.common.CommonMiddleware', # 'django.contrib.sessions.middleware.SessionMiddleware', # 'django.contrib.auth.middleware.AuthenticationMiddleware', # 'django.middleware.doc.XViewMiddleware', ) TEMPLATE_CONTEXT_PROCESSORS = () #... INSTALLED_APPS = ( #'django.contrib.auth', #'django.contrib.contenttypes', #'django.contrib.sessions', #'django.contrib.sites', 'mysite.books', )
(As were dealing with a single-element tuple here, dont forget the trailing comma. By the way, this books authors prefer to put a comma after every element of a tuple, regardless of whether the tuple has only a single element. This avoids the issue of forgetting commas, and theres no penalty for using that extra comma.)
锛堝敖绠¤繖鏄崟涓猼uple鍏冪礌锛屾垜浠篃涓嶈蹇樹簡缁撳熬鐨勯楀彿[,]銆 鍙﹀锛屾湰涔︾殑浣滆呭枩娆㈠湪 姣忎竴涓 tuple鍏冪礌鍚庨潰鍔犱竴涓楀彿锛屼笉绠″畠鏄笉鏄 鍙湁涓涓厓绱犮傝繖鏄负浜嗛伩鍏嶅繕浜嗗姞閫楀彿)
'mysite.books' refers to the books app were working on. Each app in INSTALLED_APPS is represented by its full Python path that is, the path of packages, separated by dots, leading to the app package.
'mysite.books' 鏍囪瘑 books app銆 INSTALLED_APPS 涓殑姣忎釜app閮界敤 Python鐨勮矾寰勬弿杩帮紝鍖呯殑璺緞锛岀敤灏忔暟鐐(.)鍖哄垎銆
Now that the Django app has been activated in the settings file, we can create the database tables in our database. First, lets validate the models by running this command:
鐜板湪鎴戜滑鍙互鍒涘缓鏁版嵁搴撹〃浜嗐傞鍏堬紝鐢ㄤ笅闈㈢殑鍛戒护瀵规牎楠屾ā鍨嬬殑鏈夋晥鎬э細
python manage.py validate
The validate command checks whether your models syntax and logic are correct. If all is well, youll see the message 0 errors found . If you dont, make sure you typed in the model code correctly. The error output should give you helpful information about what was wrong with the code.
validate 鍛戒护妫鏌ヤ綘鐨勬ā鍨嬬殑璇硶鍜岄昏緫鏄惁姝g‘銆傚鏋滀竴鍒囨甯革紝浣犱細鐪嬪埌 0 errors found 娑堟伅銆傚鏋滄湁闂锛屽畠浼氱粰鍑洪潪甯告湁鐢ㄧ殑閿欒淇℃伅鏉ュ府鍔╀綘 淇浣犵殑妯″瀷銆
Any time you think you have problems with your models, run python manage.py validate . It tends to catch all the common model problems.
涓鏃︿綘瑙夊緱浣犵殑妯″瀷鍙兘鏈夐棶棰橈紝杩愯 python manage.py validate 銆 瀹冨彲浠ュ府鍔╀綘鎹曡幏涓浜涘父瑙佺殑妯″瀷瀹氫箟閿欒銆
If your models are valid, run the following command for Django to generate CREATE TABLE statements for your models in the books app (with colorful syntax highlighting available if youre using Unix):
妯″瀷纭娌¢棶棰樹簡锛岃繍琛屼笅闈㈢殑鍛戒护鏉ョ敓鎴 CREATE TABLE 璇彞锛
python manage.py sqlall books
In this command, books is the name of the app. Its what you specified when you ran the command manage.py startapp . When you run the command, you should see something like this:
鍦ㄨ繖涓懡浠よ涓紝 books 鏄痑pp鐨勫悕绉般傚拰浣犺繍琛 manage.py startapp 涓殑涓鏍枫 杩愯鍛戒护鐨勭粨鏋滄槸杩欐牱鐨勶細
BEGIN; CREATE TABLE "books_publisher" ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(30) NOT NULL, "address" varchar(50) NOT NULL, "city" varchar(60) NOT NULL, "state_province" varchar(30) NOT NULL, "country" varchar(50) NOT NULL, "website" varchar(200) NOT NULL ); CREATE TABLE "books_book" ( "id" serial NOT NULL PRIMARY KEY, "title" varchar(100) NOT NULL, "publisher_id" integer NOT NULL REFERENCES "books_publisher" ("id"), "publication_date" date NOT NULL ); CREATE TABLE "books_author" ( "id" serial NOT NULL PRIMARY KEY, "salutation" varchar(10) NOT NULL, "first_name" varchar(30) NOT NULL, "last_name" varchar(40) NOT NULL, "email" varchar(75) NOT NULL, "headshot" varchar(100) NOT NULL ); CREATE TABLE "books_book_authors" ( "id" serial NOT NULL PRIMARY KEY, "book_id" integer NOT NULL REFERENCES "books_book" ("id"), "author_id" integer NOT NULL REFERENCES "books_author" ("id"), UNIQUE ("book_id", "author_id") ); CREATE INDEX books_book_publisher_id ON "books_book" ("publisher_id"); COMMIT;
Note the following:
娉ㄦ剰锛
Table names are automatically generated by combining the name of the app (books ) and the lowercase name of the model (publisher , book , and author ). You can override this behavior, as detailed in Appendix B.
鑷姩鐢熸垚鐨勮〃鍚嶆槸app鍚嶇О锛 books 锛夊拰妯″瀷鐨勫皬鍐欏悕绉 锛 publisher , book , author )鐨勭粍鍚堛 浣犲彲浠ユ寚瀹氫笉鍚岀殑琛ㄥ悕锛岃鎯呰鐪嬮檮褰 B銆
As we mentioned earlier, Django adds a primary key for each table automatically the id fields. You can override this, too.
鎴戜滑鍓嶉潰宸茬粡鎻愬埌锛孌jango涓鸿嚜鍔ㄥ姞浜嗕竴涓 id 涓婚敭锛屼綘涓鏍峰彲浠ヤ慨鏀瑰畠銆
By convention, Django appends "_id" to the foreign key field name. As you might have guessed, you can override this behavior, too.
鎸夌害瀹氾紝Django娣诲姞 "_id" 鍚庣紑鍒板閿瓧娈靛悕銆傝繖涓悓鏍蜂篃鏄彲鑷畾涔夌殑銆
The foreign key relationship is made explicit by a REFERENCES statement.
澶栭敭鏄敤 REFERENCES 璇彞鏄庣‘瀹氫箟鐨勩
These CREATE TABLE statements are tailored to the database youre using, so database-specific field types such as auto_increment (MySQL), serial (PostgreSQL), or integer primary key (SQLite) are handled for you automatically. The same goes for quoting of column names (e.g., using double quotes or single quotes). This example output is in PostgreSQL syntax.
杩欎簺 CREATE TABLE 璇彞浼氭牴鎹綘鐨勬暟鎹簱鑰屼綔璋冩暣锛岃繖鏍疯薄鏁版嵁搴撶壒瀹氱殑涓浜涘瓧娈典緥濡傦細 auto_increment (MySQL), serial (PostgreSQL), integer primary key (SQLite) 鍙互鑷姩澶勭悊銆 鍚屾牱鐨勶紝瀛楁鍚嶇О鐨勫紩鍙蜂篃鏄嚜鍔ㄥ鐞嗭紙渚嬪鍗曞紩鍙疯繕鏄弻寮曞彿锛夈 杩欎釜缁欏嚭鐨勪緥瀛愭槸Postgresql鐨勮娉曘
The sqlall command doesnt actually create the tables or otherwise touch your database it just prints output to the screen so you can see what SQL Django would execute if you asked it. If you wanted to, you could copy and paste this SQL into your database client, or use Unix pipes to pass it directly. However, Django provides an easier way of committing the SQL to the database. Run the syncdb command, like so:
sqlall 鍛戒护骞舵病鏈夊湪鏁版嵁搴撲腑鐪熸鍒涘缓鏁版嵁琛紝鍙槸鎶奡QL璇彞娈垫墦鍗板嚭鏉ャ 浣犲彲浠ユ妸杩欎簺璇彞娈垫嫹璐濆埌浣犵殑SQL瀹㈡埛绔幓鎵ц瀹冦傚綋鐒讹紝Django鎻愪緵浜嗘洿绠鍗曠殑 鏂规硶鏉ユ墽琛岃繖浜汼QL璇彞銆傝繍琛 syncdb 鍛戒护锛
python manage.py syncdb
Youll see something like this:
浣犲皢浼氱湅鍒拌繖鏍风殑鍐呭锛
Creating table books_publisher Creating table books_book Creating table books_author Installing index for books.Book model
The syncdb command is a simple sync of your models to your database. It looks at all of the models in each app in your INSTALLED_APPS setting, checks the database to see whether the appropriate tables exist yet, and creates the tables if they dont yet exist. Note that syncdb does not sync changes in models or deletions of models; if you make a change to a model or delete a model, and you want to update the database, syncdb will not handle that. (More on this later.)
syncdb 鍛戒护鏄悓姝ヤ綘鐨勬ā鍨嬪埌鏁版嵁搴撶殑涓涓畝鍗曟柟娉曘傚畠浼氭牴鎹 INSTALLED_APPS 閲岃缃殑app鏉ユ鏌ユ暟鎹簱锛 濡傛灉琛ㄤ笉瀛樺湪锛屽畠灏变細鍒涘缓瀹冦 闇瑕佹敞鎰忕殑鏄紝 syncdb 骞 涓嶈兘 鍚屾妯″瀷鐨勪慨鏀瑰埌鏁版嵁搴撱傚鏋滀綘淇敼浜嗘ā鍨嬶紝鐒跺悗浣犳兂鏇存柊 鏁版嵁搴擄紝 syncdb 鏄府涓嶄簡浣犵殑銆傦紙绋嶅悗鎴戜滑鍐嶈杩欎簺銆傦級
If you run python manage.py syncdb again, nothing happens, because you havent added any models to the books app or added any apps to INSTALLED_APPS . Ergo, its always safe to run python manage.py syncdb it wont clobber things.
濡傛灉浣犲啀娆¤繍琛 python manage.py syncdb 锛屼粈涔堜篃娌″彂鐢燂紝鍥犱负浣犳病鏈夋坊鍔犳柊鐨勬ā鍨嬫垨鑰 娣诲姞鏂扮殑app銆傛墍浠ワ紝杩愯 python manage.py syncdb 鎬绘槸瀹夊叏鐨勶紝瀹冧笉浼氭妸浜嬫儏鎼炵牳銆
If youre interested, take a moment to dive into your database servers command-line client and see the database tables Django created. You can manually run the command-line client (e.g., psql for PostgreSQL) or you can run the command python manage.py dbshell , which will figure out which command-line client to run, depending on your DATABASE_SERVER setting. The latter is almost always more convenient.
濡傛灉浣犳湁鍏磋叮锛岃姳鐐规椂闂寸敤浣犵殑SQL瀹㈡埛绔櫥褰曡繘鏁版嵁搴撴湇鍔″櫒鐪嬬湅鍒氭墠Django鍒涘缓鐨勬暟鎹〃銆 Django甯︽湁涓涓懡浠よ宸ュ叿锛 python manage.py dbshell 銆
Once youve created a model, Django automatically provides a high-level Python API for working with those models. Try it out by running python manage.py shell and typing the following:
涓鏃︿綘鍒涘缓浜嗘ā鍨嬶紝Django鑷姩涓鸿繖浜涙ā鍨嬫彁渚涗簡楂樼骇鐨凱yhton API銆 杩愯 python manage.py shell 骞惰緭鍏ヤ笅闈㈢殑鍐呭璇曡瘯鐪嬶細
>>> from books.models import Publisher >>> p1 = Publisher(name='Addison-Wesley', address='75 Arlington Street', ... city='Boston', state_province='MA', country='U.S.A.', ... website='http://www.apress.com/') >>> p1.save() >>> p2 = Publisher(name="O'Reilly", address='10 Fawcett St.', ... city='Cambridge', state_province='MA', country='U.S.A.', ... website='http://www.oreilly.com/') >>> p2.save() >>> publisher_list = Publisher.objects.all() >>> publisher_list [<Publisher: Publisher object>, <Publisher: Publisher object>]
These few lines of code accomplish quite a bit. Here are the highlights:
杩欑煭鐭嚑琛屼唬鐮佸共浜嗕笉灏戠殑浜嬨傝繖閲岀畝鍗曠殑璇翠竴涓嬶細
To create an object, just import the appropriate model class and instantiate it by passing in values for each field.
瑕佸垱寤哄璞★紝鍙渶 import 鐩稿簲妯″瀷绫伙紝骞朵紶鍏ユ瘡涓瓧娈靛煎皢鍏跺疄渚嬪寲銆
To save the object to the database, call the save() method on the object. Behind the scenes, Django executes an SQL INSERT statement here.
璋冪敤璇ュ璞$殑 save() 鏂规硶锛屽皢瀵硅薄淇濆瓨鍒版暟鎹簱涓侱jango 浼氬湪鍚庡彴鎵ц涓鏉 INSERT 璇彞銆
To retrieve objects from the database, use the attribute Publisher.objects . Fetch a list of all Publisher objects in the database with the statement Publisher.objects.all() . Behind the scenes, Django executes an SQL SELECT statement here.
浣跨敤灞炴 Publisher.objects 浠庢暟鎹簱涓幏鍙栧璞°傝皟鐢 Publisher.objects.all() 鑾峰彇鏁版嵁搴撲腑鎵鏈夌殑 Publisher 瀵硅薄銆傛鏃讹紝Django 鍦ㄥ悗鍙版墽琛屼竴鏉 SELECT SQL璇彞銆
Naturally, you can do quite a lot with the Django database API but first, lets take care of a small annoyance.
鑷劧锛屼綘鑲畾鎯虫墽琛屾洿澶氱殑Django鏁版嵁搴揂PI璇曡瘯鐪嬶紝涓嶈繃锛岃繕鏄鎴戜滑鍏堣В鍐充竴鐐圭儲浜虹殑灏忛棶棰樸
When we printed out the list of publishers, all we got was this unhelpful display that makes it difficult to tell the Publisher objects apart:
褰撴垜浠墦鍗版暣涓猵ublisher鍒楄〃鏃讹紝鎴戜滑娌℃湁寰楀埌鎯宠鐨勬湁鐢ㄧ殑淇℃伅锛
[<Publisher: Publisher object>, <Publisher: Publisher object>]
We can fix this easily by adding a method called __str__() to our Publisher object. A __str__() method tells Python how to display the string representation of an object. You can see this in action by adding a __str__() method to the three models:
鎴戜滑鍙互绠鍗曡В鍐宠繖涓棶棰橈紝鍙渶瑕佹坊鍔犱竴涓柟娉 __str__() 鍒 Publisher 瀵硅薄銆 __str__() 鏂规硶鍛婅瘔Python瑕佹庢牱鎶婂璞″綋浣滃瓧绗︿覆鏉ヤ娇鐢ㄣ 璇风湅涓嬮潰锛
from django.db import models class Publisher(models.Model): name = models.CharField(maxlength=30) address = models.CharField(maxlength=50) city = models.CharField(maxlength=60) state_province = models.CharField(maxlength=30) country = models.CharField(maxlength=50) website = models.URLField() **def __str__(self):** **return self.name** class Author(models.Model): salutation = models.CharField(maxlength=10) first_name = models.CharField(maxlength=30) last_name = models.CharField(maxlength=40) email = models.EmailField() headshot = models.ImageField(upload_to='/tmp') **def __str__(self):** **return '%s %s' % (self.first_name, self.last_name)** class Book(models.Model): title = models.CharField(maxlength=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() **def __str__(self):** **return self.title**
As you can see, a __str__() method can do whatever it needs to do in order to return a string representation. Here, the __str__() methods for Publisher and Book simply return the objects name and title, respectively, but the __str__() for Author is slightly more complex it pieces together the first_name and last_name fields. The only requirement for __str__() is that it return a string. If __str__() doesnt return a string if it returns, say, an integer then Python will raise a TypeError with a message like "__str__ returned non-string" .
灏辫薄浣犵湅鍒扮殑涓鏍凤紝 __str__() 鏂规硶杩斿洖涓涓瓧绗︿覆銆 __str__() 蹇呴』杩斿洖瀛楃涓诧紝 濡傛灉鏄叾浠栫被鍨嬶紝Python灏嗕細鎶涘嚭 TypeError 閿欒娑堟伅 "__str__ returned non-string" 鍑烘潵銆
For the changes to take effect, exit out of the Python shell and enter it again with python manage.py shell . (This is the simplest way to make code changes take effect.) Now the list of Publisher objects is much easier to understand:
涓轰簡璁╂垜浠殑淇敼鐢熸晥锛屽厛閫鍑篜ython Shell锛岀劧鍚庡啀娆¤繍琛 python manage.py shell 杩涘叆銆 鐜板湪鍒楀嚭 Publisher 瀵硅薄灏卞緢瀹规槗鐞嗚В浜嗭細
>>> from books.models import Publisher >>> publisher_list = Publisher.objects.all() >>> publisher_list [<Publisher: Addison-Wesley>, <Publisher: O'Reilly>]
Make sure any model you define has a __str__() method not only for your own convenience when using the interactive interpreter, but also because Django uses the output of __str__() in several places when it needs to display objects.
璇风‘淇濅綘鐨勬瘡涓涓ā鍨嬮噷閮藉寘鍚 __str__() 鏂规硶锛岃繖涓嶅彧鏄负浜嗕氦浜掓椂鏂逛究锛屼篃鏄洜涓 Django浼氬湪鍏朵粬涓浜涘湴鏂圭敤 __str__() 鏉ユ樉绀哄璞°
Finally, note that __str__() is a good example of adding behavior to models. A Django model describes more than the database table layout for an object; it also describes any functionality that object knows how to do. __str__() is one example of such functionality a model knows how to display itself.
鏈鍚庯紝 __str()__ 涔熸槸涓涓緢濂界殑渚嬪瓙鏉ユ紨绀烘垜浠庝箞娣诲姞 琛屼负 鍒版ā鍨嬮噷銆 Django鐨勬ā鍨嬩笉鍙槸涓哄璞″畾涔変簡鏁版嵁搴撹〃鐨勭粨鏋勶紝杩樺畾涔変簡瀵硅薄鐨勮涓恒 __str__() 灏辨槸涓涓緥瀛愭潵婕旂ず妯″瀷鐭ラ亾鎬庝箞鏄剧ず瀹冧滑鑷繁銆
Youve already seen this done: to insert a row into your database, first create an instance of your model using keyword arguments, like so:
浣犲凡缁忕煡閬撴庝箞鍋氫簡锛氬厛浣跨敤涓浜涘叧閿弬鏁板垱寤哄璞″疄渚嬶紝濡備笅锛
>>> p = Publisher(name='Apress', ... address='2855 Telegraph Ave.', ... city='Berkeley', ... state_province='CA', ... country='U.S.A.', ... website='http://www.apress.com/')
This act of instantiating a model class does not touch the database.
杩欎釜瀵硅薄瀹炰緥骞 娌℃湁 瀵规暟鎹簱鍋氫慨鏀广
To save the record into the database (i.e., to perform the SQL INSERT statement), call the objects save() method:
瑕佷繚瀛樿繖涓褰曞埌鏁版嵁搴撻噷锛堜篃灏辨槸鎵ц INSERT SQL 璇彞锛夛紝璋冪敤瀵硅薄鐨 save() 鏂规硶锛
>>> p.save()
In SQL, this can roughly be translated into the following:
鍦⊿QL閲岋紝杩欏ぇ鑷村彲浠ヨ浆鎹㈡垚杩欐牱锛
INSERT INTO book_publisher (name, address, city, state_province, country, website) VALUES ('Apress', '2855 Telegraph Ave.', 'Berkeley', 'CA', 'U.S.A.', 'http://www.apress.com/');
Because the Publisher model uses an autoincrementing primary key id , the initial call to save() does one more thing: it calculates the primary key value for the record and sets it to the id attribute on the instance:
鍥犱负 Publisher 妯″瀷鏈変竴涓嚜鍔ㄥ鍔犵殑涓婚敭 id 锛屾墍浠ョ涓娆¤皟鐢 save() 杩樺鍋氫簡涓浠朵簨锛 璁$畻杩欎釜涓婚敭鐨勫煎苟鎶婂畠璧嬪肩粰杩欎釜瀵硅薄瀹炰緥锛
>>> p.id 52 # this will differ based on your own data
Subsequent calls to save() will save the record in place, without creating a new record (i.e., performing an SQL UPDATE statement instead of an INSERT ):
鎺ヤ笅鏉ュ啀璋冪敤 save() 灏嗕笉浼氬垱寤烘柊鐨勮褰曪紝鑰屽彧鏄慨鏀硅褰曞唴瀹癸紙涔熷氨鏄 鎵ц UPDATE SQL璇彞锛岃屼笉鏄 INSERT 璇彞锛夛細
>>> p.name = 'Apress Publishing' >>> p.save()
The preceding save() statement will result in roughly the following SQL:
鍓嶉潰鎵ц鐨 save() 鐩稿綋浜庝笅闈㈢殑SQL璇彞锛
UPDATE book_publisher SET name = 'Apress Publishing', address = '2855 Telegraph Ave.', city = 'Berkeley', state_province = 'CA', country = 'U.S.A.', website = 'http://www.apress.com' WHERE id = 52;
Creating and updating data sure is fun, but it is also useless without a way to sift through that data. Weve already seen a way to look up all the data for a certain model:
鎴戜滑宸茬粡鐭ラ亾鏌ユ壘鎵鏈夋暟鎹殑鏂规硶浜嗭細
>>> Publisher.objects.all() [<Publisher: Addison-Wesley>, <Publisher: O'Reilly>, <Publisher: Apress Publishing>]
This roughly translates to this SQL:
杩欑浉褰撲簬杩欎釜SQL璇彞锛
SELECT id, name, address, city, state_province, country, website FROM book_publisher;
Note
娉ㄦ剰
Notice that Django doesnt use SELECT * when looking up data and instead lists all fields explicitly. This is by design: in certain circumstances SELECT * can be slower, and (more important) listing fields more closely follows one tenet of the Zen of Python: Explicit is better than implicit.
娉ㄦ剰鍒癉jango鍦ㄩ夋嫨鎵鏈夋暟鎹椂骞舵病鏈変娇鐢 SELECT* 锛岃屾槸鏄惧紡鍒楀嚭浜嗘墍鏈夊瓧娈点 灏辨槸杩欐牱璁捐鐨勶細 SELECT* 浼氭洿鎱紝鑰屼笖鏈閲嶈鐨勬槸鍒楀嚭鎵鏈夊瓧娈甸伒寰簡Python 鐣岀殑涓涓俊鏉★細鏄庣‘姣斾笉鏄庣‘濂姐
For more on the Zen of Python, try typing import this at a Python prompt.
鏈夊叧Python涔嬬(鎴掑緥) :-锛夛紝鍦≒ython鎻愮ず琛岃緭鍏 import this 璇曡瘯鐪嬨
Lets take a close look at each part of this Publisher.objects.all() line:
璁╂垜浠潵浠旂粏鐪嬬湅 Publisher.objects.all() 杩欒鐨勬瘡涓儴鍒嗭細
First, we have the model we defined, Publisher . No surprise here: when you want to look up data, you use the model for that data.
棣栧厛锛屾垜浠湁涓涓凡瀹氫箟鐨勬ā鍨 Publisher 銆傛病浠涔堝ソ濂囨殑锛氫綘鎯宠鏌ユ壘鏁版嵁锛 浣犲氨鐢ㄦā鍨嬫潵鑾峰緱鏁版嵁銆
Next, we have this objects business. Technically, this is a manager . Managers are discussed in detail in Appendix B. For now, all you need to know is that managers take care of all table-level operations on data including, most important, data lookup.
鍏舵锛 objects 鏄共浠涔堢殑锛熸妧鏈笂锛屽畠鏄竴涓 绠$悊鍣紙manager锛 銆 绠$悊鍣 灏嗗湪闄勫綍B璇︾粏鎻忚堪锛屽湪杩欓噷浣犲彧瑕佺煡閬撳畠澶勭悊鏈夊叧鏁版嵁琛ㄧ殑鎿嶄綔锛岀壒鍒槸鏁版嵁鏌ユ壘銆
All models automatically get a objects manager; youll use it any time you want to look up model instances.
鎵鏈夌殑妯″瀷閮借嚜鍔ㄦ嫢鏈変竴涓 objects 绠$悊鍣紱浣犲彲浠ュ湪鎯宠鏌ユ壘鏁版嵁鏃舵槸浣跨敤瀹冦
Finally, we have all() . This is a method on the objects manager that returns all the rows in the database. Though this object looks like a list, its actually a QuerySet an object that represents some set of rows from the database. Appendix C deals with QuerySets in detail. For the rest of this chapter, well just treat them like the lists they emulate.
鏈鍚庯紝杩樻湁 all() 鏂规硶銆傝繖鏄 objects 绠$悊鍣ㄨ繑鍥炴墍鏈夎褰曠殑涓涓柟娉曘 灏界杩欎釜瀵硅薄 鐪嬭捣鏉 璞′竴涓垪琛紙list锛夛紝瀹冨疄闄呮槸涓涓 QuerySet 瀵硅薄锛 杩欎釜瀵硅薄鏄暟鎹簱涓竴浜涜褰曠殑闆嗗悎銆傞檮褰旵灏嗚缁嗘弿杩癚uerySet锛岀幇鍦紝鎴戜滑 灏卞厛褰撳畠鏄竴涓豢鐪熷垪琛ㄥ璞″ソ浜嗐
Any database lookup is going to follow this general pattern well call methods on the manager attached to the model we want to query against.
鎵鏈夌殑鏁版嵁搴撴煡鎵鹃兘閬靛惊涓涓氱敤妯″紡锛氳皟鐢ㄦā鍨嬬殑绠$悊鍣ㄦ潵鏌ユ壘鏁版嵁銆
While fetching all objects certainly has its uses, most of the time were going to want to deal with a subset of the data. Well do this with the filter() method:
濡傛灉鎯宠鑾峰緱鏁版嵁鐨勪竴涓瓙闆嗭紝鎴戜滑鍙互浣跨敤 filter() 鏂规硶锛
>>> Publisher.objects.filter(name="Apress Publishing") [<Publisher: Apress Publishing>]
filter() takes keyword arguments that get translated into the appropriate SQL WHERE clauses. The preceding example would get translated into something like this:
filter() 鏍规嵁鍏抽敭瀛楀弬鏁版潵杞崲鎴 WHERE SQL璇彞銆傚墠闈㈣繖涓緥瀛 鐩稿綋浜庤繖鏍凤細
SELECT id, name, address, city, state_province, country, website FROM book_publisher WHERE name = 'Apress Publishing';
You can pass multiple arguments into filter() to narrow down things further:
浣犲彲浠ヤ紶閫掑涓弬鏁板埌 filter() 鏉ョ缉灏忛夊彇鑼冨洿锛
>>> Publisher.objects.filter(country="U.S.A.", state_province="CA") [<Publisher: Apress Publishing>]
Those multiple arguments get translated into SQL AND clauses. Thus, the example in the code snippet translates into the following:
澶氫釜鍙傛暟浼氳杞崲鎴 AND SQL璇彞锛屼緥濡傝薄涓嬮潰杩欐牱锛
SELECT id, name, address, city, state_province, country, website FROM book_publisher WHERE country = 'U.S.A.' AND state_province = 'CA';
Notice that by default the lookups use the SQL = operator to do exact match lookups. Other lookup types are available:
娉ㄦ剰锛孲QL缂虹渷鐨 = 鎿嶄綔绗︽槸绮剧‘鍖归厤鐨勶紝鍏朵粬鐨勬煡鎵剧被鍨嬪涓嬶細
>>> Publisher.objects.filter(name__contains="press") [<Publisher: Apress Publishing>]
Thats a double underscore there between name and contains . Like Python itself, Django uses the double underscore to signal that something magic is happening here, the __contains part gets translated by Django into a SQL LIKE statement:
鍦 name 鍜 contains 涔嬮棿鏈夊弻涓嬪垝绾裤傝薄Python鑷繁涓鏍凤紝Django涔熶娇鐢 鍙屼笅鍒掔嚎鏉ュ仛涓浜涘皬榄旀硶锛岃繖涓 __contains 閮ㄥ垎浼氳Django杞崲鎴 LIKE SQL璇彞锛
SELECT id, name, address, city, state_province, country, website FROM book_publisher WHERE name LIKE '%press%';
Many other types of lookups are available, including icontains (case-insensitive LIKE ), startswith and endswith , and range (SQL BETWEEN queries). Appendix C describes all of these lookup types in detail.
鍏朵粬鐨勪竴浜涙煡鎵剧被鍨嬫湁锛 icontains (澶у皬鍐欐棤鍏崇殑 LIKE ), startswith 鍜 endswith , 杩樻湁 range (SQL BETWEEN 鏌ヨ锛夈 闄勫綍C璇︾粏鍒楀嚭浜嗚繖浜涚被鍨嬬殑璇︾粏璧勬枡銆
Sometimes you want to fetch only a single object. Thats what the get() method is for:
鏈夋椂浣犲彧鎯宠幏鍙栧崟涓璞★紝杩欎釜鏃跺欎娇鐢 get() 鏂规硶锛
>>> Publisher.objects.get(name="Apress Publishing") <Publisher: Apress Publishing>
Instead of a list (rather, QuerySet), only a single object is returned. Because of that, a query resulting in multiple objects will cause an exception:
杩欐牱锛屽氨杩斿洖浜嗗崟涓璞★紝鑰屼笉鏄垪琛紙鏇村噯纭殑璇达紝QuerySet)銆 鎵浠ワ紝濡傛灉缁撴灉鏄涓璞★紝浼氬鑷存姏鍑哄紓甯革細
>>> Publisher.objects.get(country="U.S.A.") Traceback (most recent call last): ... AssertionError: get() returned more than one Publisher -- it returned 2!
A query that returns no objects also causes an exception:
濡傛灉鏌ヨ娌℃湁杩斿洖缁撴灉涔熶細鎶涘嚭寮傚父锛
>>> Publisher.objects.get(name="Penguin") Traceback (most recent call last): ... DoesNotExist: Publisher matching query does not exist.
As you play around with the previous examples, you might discover that the objects are being returned in a seemingly random order. You arent imagining things; so far we havent told the database how to order its results, so were simply getting back data in some arbitrary order chosen by the database.
鍦ㄨ繍琛屽墠闈㈢殑渚嬪瓙涓紝浣犲彲鑳藉凡缁忔敞鎰忓埌杩斿洖鐨勭粨鏋滄槸鏃犲簭鐨勩傛垜浠繕娌℃湁鍛婅瘔鏁版嵁搴 鎬庢牱瀵圭粨鏋滆繘琛屾帓搴忥紝鎵浠ユ垜浠繑鍥炵殑缁撴灉鏄棤搴忕殑銆
Thats obviously a bit silly; we wouldnt want a Web page listing publishers to be ordered randomly. So, in practice, well probably want to use order_by() to reorder our data into a useful list:
褰撶劧锛屾垜浠笉甯屾湜鍦ㄩ〉闈笂鍒楀嚭鐨勫嚭鐗堝晢鐨勫垪琛ㄦ槸鏉備贡鏃犵珷鐨勩傛垜浠敤 order_by() 鏉 鎺掑垪杩斿洖鐨勬暟鎹細
>>> Publisher.objects.order_by("name") [<Publisher: Apress Publishing>, <Publisher: Addison-Wesley>, <Publisher: O'Reilly>]
This doesnt look much different from the earlier all() example, but the SQL now includes a specific ordering:
璺熶互鍓嶇殑 all() 渚嬪瓙宸笉澶氾紝SQL璇彞閲屽浜嗘寚瀹氭帓搴忕殑閮ㄥ垎锛
SELECT id, name, address, city, state_province, country, website FROM book_publisher ORDER BY name;
We can order by any field we like:
鎴戜滑鍙互瀵逛换鎰忓瓧娈佃繘琛屾帓搴忥細
>>> Publisher.objects.order_by("address") [<Publisher: O'Reilly>, <Publisher: Apress Publishing>, <Publisher: Addison-Wesley>] >>> Publisher.objects.order_by("state_province") [<Publisher: Apress Publishing>, <Publisher: Addison-Wesley>, <Publisher: O'Reilly>]
and by multiple fields:
澶氫釜瀛楁涔熸病闂锛
>>> Publisher.objects.order_by("state_provice", "address") [<Publisher: Apress Publishing>, <Publisher: O'Reilly>, <Publisher: Addison-Wesley>]
We can also specify reverse ordering by prefixing the field name with a - (thats a minus character):
鎴戜滑杩樺彲浠ユ寚瀹氶嗗悜鎺掑簭锛屽湪鍓嶉潰鍔犱竴涓噺鍙 - 鍓嶇紑锛
>>> Publisher.objects.order_by("-name") [<Publisher: O'Reilly>, <Publisher: Apress Publishing>, <Publisher: Addison-Wesley>]
While this flexibility is useful, using order_by() all the time can be quite repetitive. Most of the time youll have a particular field you usually want to order by. In these cases, Django lets you attach a default ordering to the model:
姣忔閮借鐢 order_by() 鏄惧緱鏈夌偣鍟板棪銆 澶у鏁版椂闂翠綘閫氬父鍙細瀵规煇浜 瀛楁杩涜鎺掑簭銆傚湪杩欑鎯呭喌涓嬶紝Django璁╀綘鍙互鎸囧畾妯″瀷鐨勭己鐪佹帓搴忔柟寮忥細
class Publisher(models.Model): name = models.CharField(maxlength=30) address = models.CharField(maxlength=50) city = models.CharField(maxlength=60) state_province = models.CharField(maxlength=30) country = models.CharField(maxlength=50) website = models.URLField() def __str__(self): return self.name **class Meta:** **ordering = ["name"]**
This ordering = ["name"] bit tells Django that unless an ordering is given explicitly with order_by() , all publishers should be ordered by name.
杩欎釜 ordering = ["name"] 鍛婅瘔Django濡傛灉娌℃湁鏄剧ず鎻愪緵 order_by() , 灏辩己鐪佹寜鍚嶇О鎺掑簭銆
Whats This Meta Thing?
Meta鏄粈涔堬紵
Django uses this internal class Meta as a place to specify additional metadata about a model. Its completely optional, but it can do some very useful things. See Appendix B for the options you can put under Meta .
Django浣跨敤鍐呴儴绫籑eta瀛樻斁鐢ㄤ簬闄勫姞鎻忚堪璇ユā鍨嬬殑鍏冩暟鎹 杩欎釜绫诲畬鍏ㄥ彲浠ヤ笉瀹炵幇锛屼笉杩囦粬鑳藉仛寰堝闈炲父鏈夌敤鐨勪簨鎯呫傛煡鐪嬮檮褰旴锛屽湪Meta椤逛笅闈紝鑾峰緱鏇村閫夐」淇℃伅锛
Youve seen how you can filter data, and youve seen how you can order it. At times, of course, youre going to want to do both. In these cases, you simply chain the lookups together:
浣犲凡缁忕煡閬撴庝箞杩囨护鏁版嵁浜嗭紝鐜板湪璁╂垜浠潵鎺掑簭瀹冧滑銆備綘鍙互鍚屾椂鍋氳繖 杩囨护鍜屾帓搴忥紝寰堢畝鍗曪紝灏辫薄杩欐牱锛
>>> Publisher.objects.filter(country="U.S.A.").order_by("-name") [<Publisher: O'Reilly>, <Publisher: Apress Publishing>, <Publisher: Addison-Wesley>]
As you might expect, this translates to a SQL query with both a WHERE and an ORDER BY :
浣犲簲璇ユ病鐚滈敊锛岃浆鎹㈡垚SQL鏌ヨ灏辨槸 WHERE 鍜 ORDER BY 鐨勭粍鍚堬細
SELECT id, name, address, city, state_province, country, website FROM book_publisher WHERE country = 'U.S.A' ORDER BY name DESC;
You can keep chaining queries as long as you like. Theres no limit.
浣犲彲浠ヤ换鎰忔妸瀹冧滑涓茶捣鏉ワ紝澶氶暱閮藉彲浠ワ紝杩欓噷娌℃湁闄愬埗銆
Another common need is to look up only a fixed number of rows. Imagine you have thousands of publishers in your database, but you want to display only the first one. You can do this using Pythons standard list slicing syntax:
鍙︿竴涓父鐢ㄧ殑闇姹傚氨鏄彇鍑哄浐瀹氭暟鐩殑璁板綍銆傛兂璞′竴涓嬩綘鏈夋垚鍗冧笂涓囩殑鍑虹増鍟嗗湪浣犵殑鏁版嵁搴撻噷锛 浣嗘槸浣犲彧鎯虫樉绀虹涓涓備綘鍙互杩欐牱鍋氾細
>>> Publisher.objects.all()[0] <Publisher: Addison-Wesley>
This translates roughly to:
杩欑浉褰撲簬锛
SELECT id, name, address, city, state_province, country, website FROM book_publisher ORDER BY name LIMIT 1;
And More
杩樻湁鏇村
Weve only just scratched the surface of dealing with models, but you should now know enough to understand all the examples in the rest of the book. When youre ready to learn the complete details behind object lookups, turn to Appendix C.
鎴戜滑鍙槸鍒氭帴瑙﹀埌妯″瀷鐨勭毊姣涳紝浣犺繕蹇呴』浜嗚В鏇村鐨勫唴瀹逛互渚跨悊瑙d互鍚庣殑鑼冧緥銆 鍏蜂綋璇风湅闄勫綍C銆
To delete objects, simply call the delete() method on your object:
瑕佸垹闄ゅ璞★紝鍙渶绠鍗曠殑璋冪敤瀵硅薄鐨 delete() 鏂规硶锛
>>> p = Publisher.objects.get(name="Addison-Wesley") >>> p.delete() >>> Publisher.objects.all() [<Publisher: Apress Publishing>, <Publisher: O'Reilly>]
You can also delete objects in bulk by calling delete() on the result of some lookup:
浣犺繕鍙互鎵归噺鍒犻櫎瀵硅薄锛岄氳繃瀵规煡璇㈢殑缁撴灉璋冪敤 delete() 鏂规硶锛
>>> publishers = Publisher.objects.all() >>> publishers.delete() >>> Publisher.objects.all() []
Note
娉ㄦ剰
Deletions are permanent , so be careful! In fact, its usually a good idea to avoid deleting objects unless you absolutely have to relational databases dont do undo so well, and restoring from backups is painful.
鍒犻櫎鏄 涓嶅彲鎭㈠ 鐨勶紝鎵浠ヨ灏忓績鎿嶄綔锛佷簨瀹炰笂锛屽簲璇ュ敖閲忛伩鍏嶅垹闄ゅ璞★紝闄ら潪浣 纭疄闇瑕佸垹闄ゅ畠銆傛暟鎹簱鐨勬暟鎹仮澶嶇殑鍔熻兘閫氬父涓嶅お濂斤紝鑰屼粠澶囦唤鏁版嵁鎭㈠鏄緢鐥涜嫤鐨勩
Its often a good idea to add active flags to your data models. You can look up only active objects, and simply set the active field to False instead of deleting the object. Then, if you realize youve made a mistake, you can simply flip the flag back.
閫氬父鏇村ソ鐨勬柟娉曟槸缁欎綘鐨勬暟鎹ā鍨嬫坊鍔犳縺娲绘爣蹇椼備綘鍙互鍙湪婵娲荤殑瀵硅薄涓煡鎵撅紝 瀵逛簬涓嶉渶瑕佺殑瀵硅薄锛屽皢婵娲诲瓧娈靛艰涓 False , 鑰屼笉鏄垹闄ゅ璞°傝繖鏍凤紝 濡傛灉涓鏃︿綘璁や负鍋氶敊浜嗙殑璇濓紝鍙渶鎶婃爣蹇楅噸璁惧洖鏉ュ氨鍙互浜嗐
When we introduced the syncdb command earlier in this chapter, we noted that syncdb merely creates tables that dont yet exist in your database it does not sync changes in models or perform deletions of models. If you add or change a models field, or if you delete a model, youll need to make the change in your database manually. This section explains how to do that.
褰撴垜浠湪杩欎竴绔犵殑鍓嶉潰浠嬬粛 syncdb 鍛戒护鐨勬椂鍊欙紝鎴戜滑寮鸿皟 syncdb 浠呬粎鍒涘缓鏁版嵁搴撲腑涓嶅瓨鍦ㄧ殑琛紝鑰屼笉浼氬悓姝ユā鍨嬬殑淇敼鎴栬呭垹闄ゅ埌鏁版嵁搴撱傚鏋滀綘娣诲姞鎴栬呬慨鏀逛簡妯″瀷鐨勪竴涓瓧娈碉紝鎴栬呭垹闄や竴涓ā鍨嬶紝浣犲繀椤绘墜鍔ㄦ敼鍙樹綘鐨勬暟鎹簱銆備笅闈㈡垜浠湅鐪嬫庝箞鏉ュ仛銆
When dealing with schema changes, its important to keep a few things in mind about how Djangos database layer works:
褰撴垜浠鐞嗚〃缁撴瀯鐨勪慨鏀规椂锛岃鏃跺埢鎯崇潃 Django 鐨勬暟鎹簱灞傛槸濡備綍宸ヤ綔鐨勶細
Django will complain loudly if a model contains a field that has not yet been created in the database table. This will cause an error the first time you use the Django database API to query the given table (i.e., it will happen at code execution time, not at compilation time).
濡傛灉妯″瀷涓寘鍚竴涓湪鏁版嵁搴撲腑骞朵笉瀛樺湪鐨勫瓧娈碉紝Django浼氬ぇ澹版姳鎬ㄧ殑銆傝繖鏍峰綋浣犵涓娆¤皟鐢―jango鐨勬暟鎹簱API鏉ユ煡璇㈢粰瀹氱殑琛ㄦ椂灏变細鍑洪敊锛堜篃灏辨槸璇达紝瀹冧細鍦ㄦ墽琛岀殑鏃跺欏嚭閿欙紝鑰屼笉鏄紪璇戠殑鏃跺欙級
Django does not care if a database table contains columns that are not defined in the model.
Django骞朵笉鍏冲績鏁版嵁搴撹〃涓槸鍚﹀瓨鍦ㄦ病鏈夊湪妯″瀷涓畾涔夌殑鍒
Django does not care if a database contains a table that is not represented by a model.
Django骞朵笉鍏冲績鏁版嵁搴撲腑鏄惁鍖呭惈娌℃湁琚ā鍨嬫弿杩扮殑琛
Making schema changes is a matter of changing the various pieces the Python code and the database itself in the right order.
淇敼琛ㄧ粨鏋勪篃灏辨槸鎸夌収姝g‘鐨勯『搴忎慨鏀瑰悇绉峆ython浠g爜鍜屾暟鎹簱鏈韩
When adding a field to a table/model in a production setting, the trick is to take advantage of the fact that Django doesnt care if a table contains columns that arent defined in the model. The strategy is to add the column in the database, and then update the Django model to include the new field.
褰撴寜鐓т骇鍝侀渶姹傚悜涓涓〃/妯″瀷娣诲姞瀛楁鏃讹紝Django涓嶅叧蹇冧竴涓〃鐨勫垪鏄惁鍦ㄦā鍨嬩腑瀹氫箟锛屾垜浠彲浠ュ埄鐢ㄨ繖涓皬鎶宸э紝鍏堝湪鏁版嵁搴撲腑娣诲姞鍒楋紝鐒跺悗鍐嶆敼鍙樻ā鍨嬩腑瀵瑰簲鐨勫瓧娈点
However, theres a bit of a chicken-and-egg problem here, because in order to know how the new database column should be expressed in SQL, you need to look at the output of Djangos manage.py sqlall command, which requires that the field exist in the model. (Note that youre not required to create your column with exactly the same SQL that Django would, but its a good idea to do so, just to be sure everythings in sync.)
鐒惰岋紝杩欓噷鎬绘槸瀛樺湪鍏堟湁楦¤繕鏄厛鏈夎泲鐨勯棶棰橈紝涓轰簡寮勬竻鏂扮殑鏁版嵁鍒楁庝箞鐢⊿QL鎻忚堪锛屼綘闇瑕佹煡鐪 manage.py sqlall 鐨勬墽琛岀粨鏋滐紝瀹冨垪鍑轰簡妯″瀷涓凡缁忓瓨鍦ㄧ殑瀛楁銆傦紙娉ㄦ剰锛氫綘涓嶉渶瑕佸儚Django涓殑SQL涓妯′竴鏍风殑鍒涘缓浣犵殑鍒楋紝浣嗘槸杩欑‘瀹炴槸涓涓ソ涓绘剰锛屼粠鑰屼繚璇佹墍鏈夐兘鏄悓姝ョ殑锛
The solution to the chicken-and-egg problem is to use a development environment instead of making the changes on a production server. (You are using a testing/development environment, right?) Here are the detailed steps to take.
瑙e喅楦″拰铔嬬殑闂鐨勬柟娉曞氨鏄厛鍦ㄥ紑鍙戠幆澧冭屼笉鏄彂甯冩湇鍔″櫒涓婁慨鏀广傦紙浣犵幇鍦ㄧ敤鐨勫氨鏄祴璇/寮鍙戠幆澧冿紝涓嶆槸鍚楋紵锛変笅闈㈡槸璇︾粏鐨勬楠ゃ
First, take these steps in the development environment (i.e., not on the production server):
棣栧厛锛屽湪寮鍙戠幆澧冧腑鎵ц涓嬮潰鐨勬楠わ紙涔熷氨鏄锛屼笉鏄湪鍙戝竷鏈嶅姟鍣ㄤ笂):
Add the field to your model.
鎶婅繖涓瓧娈垫坊鍔犲埌浣犵殑妯″瀷涓.
Run manage.py sqlall [yourapp] to see the new CREATE TABLE statement for the model. Note the column definition for the new field.
杩愯 manage.py sqlall [yourapp] 浼氱湅鍒版ā鍨嬬殑鏂扮殑 CREATE TABLE 璇彞銆 娉ㄦ剰鏂扮殑瀛楁鐨勫垪瀹氫箟銆
Start your databases interactive shell (e.g., psql or mysql , or you can use manage.py dbshell ). Execute an ALTER TABLE statement that adds your new column.
鍚姩鎮ㄧ殑鏁版嵁搴撲氦浜抯hell(涔熷氨鏄 psql 鎴 mysql 锛 鎴栬呮偍涔熷彲浠ヤ娇鐢 manage.py dbshell )銆 鎵ц涓涓 ALTER TABLE 璇彞锛屾坊鍔犳偍鐨勬柊鍒椼
(Optional.) Launch the Python interactive shell with manage.py shell and verify that the new field was added properly by importing the model and selecting from the table (e.g., MyModel.objects.all()[:5] ).
4. (鍙)鐢 manage.py shell 鍚姩Python浜や簰寮弒hell锛屽苟閫氳繃寮曞叆妯″瀷骞堕夋嫨琛 楠岃瘉鏂扮殑瀛楁宸茶姝g‘娣诲姞(姣斿锛 MyModel.objects.all()[:5] )銆
Then on the production server perform these steps:
鐒跺悗鍦ㄥ彂甯冩湇鍔″櫒涓婃墽琛屼笅闈㈢殑姝ラ锛
Start your databases interactive shell.
鍚姩浣犵殑鏁版嵁搴撶殑浜や簰寮忓懡浠よ锛
Execute the ALTER TABLE statement you used in step 3 of the development environment steps.
鎵ц ALTER TABLE 璇彞锛屼篃灏辨槸鍦ㄥ紑鍙戠幆澧冧腑绗3姝ユ墽琛岀殑璇彞锛
Add the field to your model. If youre using source-code revision control and you checked in your change in development environment step 1, now is the time to update the code (e.g., svn update , with Subversion) on the production server.
娣诲姞瀛楁鍒颁綘鐨勬ā鍨嬩腑銆傚鏋滀綘鍦ㄥ紑鍙戞椂浣跨敤浜嗙増鏈帶鍒剁郴缁熷苟checkin浜嗕綘鐨勪慨鏀癸紝鐜板湪鍙互鏇存柊 浠g爜鍒板彂甯冩湇鍔″櫒涓婁簡锛堜緥濡傦紝浣跨敤Subverison鐨勮瘽灏辨槸 svn update )銆
Restart the Web server for the code changes to take effect.
閲嶅惎Web鏈嶅姟鍣ㄤ互浣夸唬鐮佷慨鏀圭敓鏁堛
For example, lets walk through what wed do if we added a num_pages field to the Book model described earlier in this chapter. First, wed alter the model in our development environment to look like this:
渚嬪锛岃鎴戜滑閫氳繃缁 Book 妯″瀷娣诲姞涓涓 num_pages 瀛楁鏉ユ紨绀轰竴涓嬨 棣栧厛锛屾垜浠湪寮鍙戠幆澧冧腑杩欐牱淇敼妯″瀷锛
class Book(models.Model): title = models.CharField(maxlength=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField() **num_pages = models.IntegerField(blank=True, null=True)** def __str__(self): return self.title
(Note: Read the Adding NOT NULL Columns sidebar for important details on why we included blank=True and null=True .)
锛堟敞鎰忥細鎴戜滑杩欓噷涓轰粈涔堝啓 blank=True 鍜 null=True 鍛紵闃呰棰樹负鈥滄坊鍔犻潪绌哄瓧娈碘濈殑渚ц竟鏍忚幏鍙栨洿澶氫俊鎭傦級
Then wed run the command manage.py sqlall books to see the CREATE TABLE statement. It would look something like this:
鐒跺悗鎴戜滑杩愯鍛戒护 manage.py sqlall books 鏉ュ緱鍒 CREATE TABLE 璇彞銆傚畠浠湅璧锋潵 鏄繖鏍风殑锛
CREATE TABLE "books_book" ( "id" serial NOT NULL PRIMARY KEY, "title" varchar(100) NOT NULL, "publisher_id" integer NOT NULL REFERENCES "books_publisher" ("id"), "publication_date" date NOT NULL, "num_pages" integer NULL );
The new column is represented like this:
鏂板姞鐨勫瓧娈礢QL鎻忚堪鏄繖鏍风殑锛
"num_pages" integer NULL
Next, wed start the databases interactive shell for our development database by typing psql (for PostgreSQL), and wed execute the following statements:
鎺ヤ笅鏉ワ紝鎴戜滑鍚姩鏁版嵁搴撲氦浜掑懡浠ょ晫闈紝渚嬪Postgresql鏄墽琛 psql , 骞舵墽琛屼笅闈㈢殑璇彞锛
ALTER TABLE books_book ADD COLUMN num_pages integer;
Adding NOT NULL Columns
娣诲姞闈炵┖瀛楁锛圢OT NULL锛
Theres a subtlety here that deserves mention. When we added the num_pages field to our model, we included the blank=True and null=True options. We did this because a database column will contain NULL values when you first create it.
杩欓噷鏈変竴涓娉ㄦ剰鐨勫湴鏂广傚湪娣诲姞 num_pages 瀛楁鏃舵垜浠娇鐢ㄤ簡 blank=True 鍜 null=True 鍙夐」銆 鎴戜滑涔嬫墍浠ヨ繖涔堝仛鏄洜涓哄湪鏁版嵁搴撳垱寤烘椂鎴戜滑鎯冲厑璁稿瓧娈靛间负NULL銆
However, its also possible to add columns that cannot contain NULL values. To do this, you have to create the column as NULL , then populate the columns values using some default(s), and then alter the column to set the NOT NULL modifier. For example:
褰撶劧锛屼篃鍙互鍦ㄦ坊鍔犲瓧娈垫椂璁剧疆鍊间笉鑳戒负NULL銆傝瀹炵幇杩欎釜锛屼綘涓嶅緱涓嶅厛鍒涘缓涓涓 NULL 瀛楁锛 浣跨敤缂虹渷鍊硷紝鍐嶄慨鏀瑰瓧娈靛埌 NOT NULL 銆備緥濡傦細
BEGIN; ALTER TABLE books_book ADD COLUMN num_pages integer; UPDATE books_book SET num_pages=0; ALTER TABLE books_book ALTER COLUMN num_pages SET NOT NULL; COMMIT;
If you go down this path, remember that you should leave off blank=True and null=True in your model.
濡傛灉浣犺繖鏍峰仛浜嗭紝 璁板緱瑕佹妸 blank=True 鍜 null=True 浠庝綘鐨勬ā鍨嬩腑鎷挎帀銆
After the ALTER TABLE statement, wed verify that the change worked properly by starting the Python shell and running this code:
鎵ц瀹 ALTER TABLE 璇彞锛 鎴戜滑纭涓涓嬩慨鏀规槸鍚︽纭紝鍚姩Python浜や簰鐣岄潰骞舵墽琛屼笅闈㈣鍙ワ細
>>> from mysite.books.models import Book >>> Book.objects.all()[:5]
If that code didnt cause errors, wed switch to our production server and execute the ALTER TABLE statement on the production database. Then, wed update the model in the production environment and restart the Web server.
濡傛灉娌℃湁閿欒锛屾垜浠氨鍙互杞埌鍙戝竷鏈嶅姟鍣ㄦ潵鍦ㄦ暟鎹簱涓婃墽琛 ALTER TABLE 璇彞浜嗐傜劧鍚庯紝 鍐嶆洿鏂版ā鍨嬪苟閲嶅惎WEB鏈嶅姟鍣ㄣ
Removing a field from a model is a lot easier than adding one. To remove a field, just follow these steps:
浠庢ā鍨嬮噷鍒犻櫎涓涓瓧娈靛彲瑕佹瘮澧炲姞瀹冪畝鍗曞浜嗐傚垹闄や竴涓瓧娈典粎闇瑕佸仛濡備笅鎿嶄綔锛
Remove the field from your model and restart the Web server.
浠庝綘鐨勬ā鍨嬮噷鍒犻櫎杩欎釜瀛楁锛屽苟閲嶅惎Web鏈嶅姟鍣ㄣ
Remove the column from your database, using a command like this:
浣跨敤濡備笅闈㈡墍绀虹殑鍛戒护锛屼粠浣犵殑鏁版嵁搴撲腑鍒犳帀璇ュ垪锛
ALTER TABLE books_book DROP COLUMN num_pages;
Because many-to-many fields are different than normal fields, the removal process is different:
鍥犱负many-to-many瀛楁鍚屾櫘閫氬瓧娈垫湁浜涗笉鍚岋紝瀹冪殑鍒犻櫎杩囩▼涔熶笉涓鏍凤細
Remove the ManyToManyField from your model and restart the Web server.
鍒犻櫎鎺変綘鐨勬ā鍨嬮噷鐨 ManyToManyField 锛屽苟涓旈噸鍚疻eb鏈嶅姟鍣ㄣ
Remove the many-to-many table from your database, using a command like this:
浣跨敤濡備笅闈㈡墍绀虹殑鍛戒护锛屽垹闄ゆ帀浣犳暟鎹簱閲岀殑many-to-many琛細
DROP TABLE books_books_publishers;
Removing a model entirely is as easy as removing a field. To remove a model, just follow these steps:
瀹屽叏鍒犻櫎涓涓ā鍨嬪氨鍍忓垹闄や竴涓瓧娈典竴鏍风畝鍗曘傚垹闄ゆā鍨嬩粎闇瑕佸仛濡備笅姝ラ锛
Remove the model from your models.py file and restart the Web server.
灏嗘妯″瀷浠庝綘鐨 models.py 鏂囦欢閲屽垹闄わ紝骞朵笖閲嶅惎Web鏈嶅姟鍣ㄣ
Remove the table from your database, using a command like this:
浣跨敤濡備笅鐨勫懡浠わ紝灏嗘琛ㄤ粠浣犵殑鏁版嵁搴撲腑鍒犻櫎锛
DROP TABLE books_book;
Once youve defined your models, the next step is to populate your database with data. You might have legacy data, in which case Chapter 16 will give you advice about integrating with legacy databases. You might rely on site users to supply your data, in which case Chapter 7 will teach you how to process user-submitted form data.
涓鏃︿綘瀹氫箟浜嗕綘鐨勬ā鍨嬶紝鎺ヤ笅鏉ュ氨鏄鎶婃暟鎹鍏ユ暟鎹簱閲屼簡銆備綘鍙兘宸茬粡鏈夌幇鎴愮殑鏁版嵁浜嗭紝璇风湅绗崄鍏珷锛屽浣曢泦鎴愮幇鏈夌殑鏁版嵁搴撱備篃鍙兘鏁版嵁鏄敤鎴锋彁渚涚殑锛岀涓冪珷涓繕浼氭暀浣犳庝箞澶勭悊鐢ㄦ埛鎻愪氦鐨勬暟鎹
But in some cases, you or your team might need to enter data manually, in which case it would be helpful to have a Web-based interface for entering and managing data. The next chapter covers Djangos admin interface, which exists precisely for that reason.
鏈夋椂鍊欙紝浣犲拰浣犵殑鍥㈤槦鎴愬憳涔熼渶瑕佹墜宸ヨ緭鍏ユ暟鎹紝杩欐椂鍊欏鏋滆兘鏈変竴涓熀浜嶹eb鐨勬暟鎹緭鍏ュ拰绠$悊鐨勭晫闈 灏卞緢鏈夊府鍔┿備笅涓绔犲皢璁茶堪Django鐨勭鐞嗙晫闈紝瀹冨氨鏄笓闂ㄥ共杩欎釜娲荤殑銆
鍏充簬鏈瘎娉ㄧ郴缁
鏈珯浣跨敤涓婁笅鏂囧叧鑱旂殑璇勬敞绯荤粺鏉ユ敹闆嗗弽棣堜俊鎭備笉鍚屼簬涓鑸鏁寸珷鍋氳瘎娉ㄧ殑鍋氭硶锛 鎴戜滑鍏佽浣犲姣忎竴涓嫭绔嬬殑鈥滄枃鏈潡鈥濆仛璇勬敞銆備竴涓滄枃鏈潡鈥濈湅璧锋潵鏄繖鏍风殑锛
涓涓滄枃鏈潡鈥濇槸涓涓钀斤紝涓涓垪琛ㄩ」锛屼竴娈典唬鐮侊紝鎴栬呭叾浠栦竴灏忔鍐呭銆 浣犻変腑瀹冧細楂樹寒搴︽樉绀:
瑕佸鏂囨湰鍧楀仛璇勬敞锛屼綘鍙渶瑕佺偣鍑诲畠鏃佽竟鐨勬爣璇嗗潡:
鎴戜滑浼氫粩缁嗛槄璇绘瘡涓瘎璁猴紝濡傛灉鍙兘鐨勮瘽鎴戜滑涔熶細鎶婅瘎娉ㄨ冭檻鍒版湭鏉ョ殑鐗堟湰涓幓:
濡傛灉浣犳効鎰忎綘鐨勮瘎娉ㄨ閲囩敤锛岃纭繚鐣欎笅浣犵殑鍏ㄥ悕 (娉ㄦ剰涓嶆槸鏄电О鎴栫畝绉帮級
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.