創建項目mysitehtml
各文件和目錄解釋:python
mysite/
目錄與Django無關,只是你項目的容器,能夠任意重命名。manage.py
:一個命令行工具,用於與Django進行不一樣方式的交互腳本,很是重要!mysite/
目錄是真正的項目文件包裹目錄,它的名字是你引用內部文件的包名,例如:mysite.urls
。mysite/__init__.py
:一個定義包的空文件。mysite/settings.py
:項目的主配置文件,很是重要!mysite/urls.py
:路由文件,全部的任務都是從這裏開始分配,至關於Django驅動站點的內容表格,很是重要!mysite/wsgi.py
:一個基於WSGI的web服務器進入點,提供底層的網絡通訊功能,一般不用關心。啓動開發服務器mysql
或進入mystie項目的根目錄,輸入下面的命令:程序員
$ python manage.py runserver
Django提供了一個用於開發的web服務器,使你無需配置一個相似Ngnix的生產服務器,就能讓站點運行起來。這是一個由Python編寫的輕量級服務器,簡易而且不安全,所以不要將它用於生產環境。web
打開瀏覽器,訪問http://127.0.0.1:8000/
,你將看到Django的火箭歡迎界面,一切OK!正則表達式
在 Django 中,每個應用(app)都是一個 Python 包,而且遵循着相同的約定。Django 自帶一個工具,能夠幫你生成應用的基礎目錄結構。sql
app應用與project項目的區別:shell
一般app將它們放在與manage.py
腳本同級的目錄下,這樣方便導入文件。數據庫
進入mysite項目根目錄,確保與manage.py
文件處於同一級,輸入下述命令django
python manage.py startapp polls
系統會自動生成 polls應用的目錄,其結構以下
在Pycharm中,沒有能夠建立app的圖形化按鈕,須要在下方的Terminal
終端中輸入命令
在polls/views.py
文件中,編寫代碼
from django.http import HttpResponse def index(request): return HttpResponse("Hello, world. You're at the polls index.")
爲了調用該視圖,咱們還須要編寫urlconf,也就是路由。如今,在polls目錄中新建一個文件,名字爲urls.py
,在其中輸入代碼以下:
from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), ]
接下來,在項目的主urls.py文件中添加urlpattern
條目,指向咱們剛纔創建的polls這個app獨有的urls文件,
這裏須要導入include模塊。打開mysite/urls.py
文件,代碼以下
from django.contrib import admin from django.urls import include, path urlpatterns = [ path('polls/', include('polls.urls')), path('admin/', admin.site.urls), ]
include語法至關於多級路由,它把接收到的url地址去除與此項匹配的部分,將剩下的字符串傳遞給下一級路由
include的背後是一種即插即用的思想。項目根路由不關心具體app的路由策略,只管往指定的二級路由轉發,實現了應用解耦。
app所屬的二級路由能夠根據本身的須要隨意編寫,不會和其它的app路由發生衝突。app目錄能夠放置在任何位置,而不用修改路由。這是軟件設計裏很常見的一種模式。
好了,路由設置成功後,啓動服務器,而後在瀏覽器中訪問地址http://localhost:8000/polls/
。一切正常的話,你將看到「Hello, world. You’re at the polls index.」
路由系統中最重要的path()方法能夠接收4個參數,其中2個是必須的:route
和view
,以及2個可選的參數:kwargs
和name
。
route:
route 是一個匹配 URL 的準則(相似正則表達式)。當 Django 響應一個請求時,它會從 urlpatterns 的第一項開始,按順序依次匹配列表中的項,直到找到匹配的項,
而後執行該條目映射的視圖函數或下級路由,其後的條目將再也不繼續匹配。所以,url路由的編寫順序很是重要!
須要注意的是,route不會匹配 GET 和 POST 參數或域名。例如,URLconf 在處理請求 https://www.example.com/myapp/
時,
它會嘗試匹配 myapp/
。處理請求 https://www.example.com/myapp/?page=3
時,也只會嘗試匹配 myapp/
。
view:
view指的是處理當前url請求的視圖函數。當Django匹配到某個路由條目時,自動將封裝的HttpRequest
對象做爲第一個參數,被「捕獲」的參數以關鍵字參數的形式,傳遞給該條目指定的視圖view。
kwargs:
任意數量的關鍵字參數能夠做爲一個字典傳遞給目標視圖。
name:
對你的URL進行命名,讓你可以在Django的任意處,尤爲是模板內顯式地引用它。這是一個很是強大的功能,至關於給URL取了個全局變量名,不會將url匹配地址寫死
打開mysite/settings.py
配置文件,這是整個Django項目的設置中心。Django默認使用SQLite數據庫,
由於Python源生支持SQLite數據庫,因此你無須安裝任何程序,就能夠直接使用它。固然,若是你是在建立一個實際的項目,可使用相似PostgreSQL的數據庫
# Database # https://docs.djangoproject.com/en/2.1/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } }
若是你想使用其餘的數據庫,請先安裝相應的數據庫操做模塊,並將settings文件中DATABASES位置的’default’
的鍵值進行相應的修改,用於鏈接你的數據庫。其中:
ENGINE(引擎):能夠是django.db.backends.sqlite3
、django.db.backends.postgresql
、django.db.backends.mysql
、django.db.backends.oracle
,固然其它的也行。
NAME(名稱):相似Mysql數據庫管理系統中用於保存項目內容的數據庫的名字。若是你使用的是默認的SQLite,那麼數據庫將做爲一個文件將存放在你的本地機器內,
此時的NAME應該是這個文件的完整絕對路徑包括文件名,默認值os.path.join(BASE_DIR, ’db.sqlite3’)
,將把該文件儲存在你的項目目錄下。
基於pymysql操做Mysql數據庫的例子
# Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases import pymysql # 必定要添加這兩行!經過pip install pymysql! pymysql.install_as_MySQLdb() DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'cnblog', 'USER': 'root', 'PASSWORD': '111', 'HOST': '127.0.0.1', 'PORT': 3306 } } # mysql orm轉換sql日誌 LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
注意:
CREATE DATABASE database_name;
。Django不會自動幫你作這一步工做。在修改settings文件時,請順便將TIME_ZONE
設置爲國內所在的時區Asia/Shanghai
。
同時,請注意settings文件中頂部的INSTALLED_APPS
設置項。它列出了全部的項目中被激活的Django應用(app)。你必須將你自定義的app註冊在這裏。每一個應用能夠被多個項目使用,而且能夠打包和分發給其餘人在他們的項目中使用。
默認狀況,INSTALLED_APPS
中會自動包含下列條目,它們都是Django自動生成的:
上面的一些應用也須要創建一些數據庫表,因此在使用它們以前咱們要在數據庫中建立這些表。使用下面的命令建立數據表:
python manage.py migrate
如今,咱們來定義模型model,模型本質上就是數據庫表的佈局,再附加一些元數據。
Django經過自定義Python類的形式來定義具體的模型,每一個模型的物理存在方式就是一個Python的類Class,每一個模型表明數據庫中的一張表,每一個類的實例表明數據表中的一行數據,類中的每一個變量表明數據表中的一列字段。
Django經過模型,將Python代碼和數據庫操做結合起來,實現對SQL查詢語言的封裝。也就是說,你能夠不會管理數據庫,能夠不會SQL語言,你一樣能經過Python的代碼進行數據庫的操做。
Django經過ORM對數據庫進行操做,奉行代碼優先的理念,將Python程序員和數據庫管理員進行分工解耦。
在這個簡單的投票應用中,咱們將建立兩個模型:Question
和Choice
。Question包含一個問題和一個發佈日期。Choice包含兩個字段:該選項的文本描述和該選項的投票數。
每一條Choice都關聯到一個Question。這些都是由Python的類來體現,編寫的全是Python的代碼,不接觸任何SQL語句。如今,編輯polls/models.py
文件
from django.db import models class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0)
上面的代碼很是簡單明瞭。每個類都是django.db.models.Model
的子類。每個字段都是Field
類的一個實例,例如用於保存字符數據的CharField和用於保存時間類型的DateTimeField,它們告訴Django每個字段保存的數據類型。
每個Field實例的名字就是字段的名字(如: question_text 或者 pub_date )。在你的Python代碼中會使用這個值,你的數據庫也會將這個值做爲表的列名。
一些Field類必須提供某些特定的參數。例如CharField須要你指定max_length。這不只是數據庫結構的須要,一樣也用於數據驗證功能。
有必填參數,固然就會有可選參數,好比在votes裏咱們將其默認值設爲0.
最後請注意,咱們使用ForeignKey
定義了一個外鍵關係。它告訴Django,每個Choice關聯到一個對應的Question(注意要將外鍵寫在‘多’的一方)。Django支持通用的數據關係:一對一,多對一和多對多。
上面的代碼看着有點少,其實包含了大量的信息,據此,Django會作下面兩件事:
可是,首先咱們得先告訴Django項目,咱們要使用投票app。
要將應用添加到項目中,須要在INSTALLED_APPS
設置中增長指向該應用的配置文件的連接。對於本例的投票應用,它的配置類文件PollsConfig是polls/apps.py
,
因此它的點式路徑爲polls.apps.PollsConfig
。咱們須要在INSTALLED_APPS
中,將該路徑添加進去,實際上,在多數狀況下,咱們簡寫成‘polls’就能夠了:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'polls' ]
如今Django已經知道你的投票應用的存在了,並把它加入了項目你們庭。
咱們須要再運行下一個命令:
python manage.py makemigrations polls
經過運行makemigrations
命令,Django 會檢測你對模型文件的修改,也就是告訴Django你對模型有改動,而且你想把這些改動保存爲一個「遷移(migration)」。
migrations
是Django保存模型修改記錄的文件,這些文件保存在磁盤上。在例子中,它就是polls/migrations/0001_initial.py
,你能夠打開它看看,裏面保存的都是人類可讀而且可編輯的內容,方便你隨時手動修改。
接下來有一個叫作migrate
的命令將對數據庫執行真正的遷移動做。可是在此以前,讓咱們先看看在migration的時候實際執行的SQL語句是什麼。有一個叫作sqlmigrate
的命令能夠展現SQL語句
python manage.py sqlmigrate polls 0001
請注意:
question
和choice
。 ( 你能夠重寫此行爲。)若是你感興趣,也能夠運行python manage.py check
命令,它將檢查項目中的錯誤,並不實際進行遷移或者連接數據庫的操做。
$ python manage.py migrate
migrate命令對全部還未實施的遷移記錄進行操做,本質上就是將你對模型的修改體現到數據庫中具體的表上面。Django經過一張叫作django_migrations的表,記錄並跟蹤已經實施的migrate動做,經過對比得到哪些migrations還沒有提交。
migrations的功能很是強大,容許你隨時修改你的模型,而不須要刪除或者新建你的數據庫或數據表,在不丟失數據的同時,實時動態更新數據庫。咱們將在後面的章節對此進行深刻的闡述,可是如今,只須要記住修改模型時的操做分三步:
python manage.py makemigrations
爲改動建立遷移記錄;python manage.py migrate
,將操做同步到數據庫。mysql> show tables; +----------------------------+ | Tables_in_poll | +----------------------------+ | auth_group | | auth_group_permissions | | auth_permission | | auth_user | | auth_user_groups | | auth_user_user_permissions | | django_admin_log | | django_content_type | | django_migrations | | django_session | | polls_choice | | polls_question | +----------------------------+ 12 rows in set (0.00 sec)
下面,讓咱們進入Python交互環境,嘗試使用Django提供的數據庫訪問API。要進入Python的shell,請輸入命令
python manage.py shell
相比較直接輸入「python」命令的方式進入Python環境,調用manage.py
參數能將DJANGO_SETTINGS_MODULE
環境變量導入,
它將自動按照mysite/settings.py
中的設置,配置好你的python shell環境,這樣,你就能夠導入和調用任何你項目內的模塊了。
先進入一個純淨的python shell環境,而後啓動Django。
當你進入shell後,嘗試一下下面的API吧:
>>> from polls.models import Question, Choice # 導入咱們寫的模型類 # 如今系統內尚未questions對象 >>> Question.objects.all() <QuerySet []> # 建立一個新的question對象 # Django推薦使用timezone.now()代替python內置的datetime.datetime.now() # 這個timezone就來自於Django的依賴庫pytz from django.utils import timezone >>> q = Question(question_text="What's new?", pub_date=timezone.now()) # 你必須顯式的調用save()方法,才能將對象保存到數據庫內 >>> q.save() # 默認狀況,你會自動得到一個自增的名爲id的主鍵 >>> q.id 1 # 經過python的屬性調用方式,訪問模型字段的值 >>> q.question_text "What's new?" >>> q.pub_date datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>) # 經過修改屬性來修改字段的值,而後顯式的調用save方法進行保存。 >>> q.question_text = "What's up?" >>> q.save() # objects.all() 用於查詢數據庫內的全部questions >>> Question.objects.all() <QuerySet [<Question: Question object>]>
上面的<Question: Question object>
是一個不可讀的內容展現,你沒法從中得到任何直觀的信息,爲此咱們須要一點小技巧,讓Django在打印對象時顯示一些咱們指定的信息。
返回polls/models.py
文件,修改一下question和Choice這兩個類,代碼以下:
from django.db import models class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') def __str__(self): return self.question_text class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0) def __str__(self): return self.choice_text
這個技巧不但對你打印對象時頗有幫助,在你使用Django的admin站點時也一樣有幫助。
從新啓動一個新的python shell,再來看看其餘的AP
>>> from polls.models import Question, Choice # 先看看__str__()的效果,直觀多了吧? >>> Question.objects.all() <QuerySet [<Question: What's up?>]> # Django提供了大量的關鍵字參數查詢API >>> Question.objects.filter(id=1) <QuerySet [<Question: What's up?>]> >>> Question.objects.filter(question_text__startswith='What') <QuerySet [<Question: What's up?>]> # 獲取今年發佈的問卷 >>> from django.utils import timezone >>> current_year = timezone.now().year >>> Question.objects.get(pub_date__year=current_year) <Question: What's up?> # 查詢一個不存在的ID,會彈出異常 >>> Question.objects.get(id=2) Traceback (most recent call last): ... DoesNotExist: Question matching query does not exist. # Django爲主鍵查詢提供了一個縮寫:pk。下面的語句和Question.objects.get(id=1)效果同樣. >>> Question.objects.get(pk=1) <Question: What's up?> # 看看咱們自定義的方法用起來怎麼樣 >>> q = Question.objects.get(pk=1) >>> q.was_published_recently() True # 讓咱們試試主鍵查詢 >>> q = Question.objects.get(pk=1) # 顯示全部與q對象有關係的choice集合,目前是空的,尚未任何關聯對象。 >>> q.choice_set.all() <QuerySet []> # 建立3個choices. >>> q.choice_set.create(choice_text='Not much', votes=0) <Choice: Not much> >>> q.choice_set.create(choice_text='The sky', votes=0) <Choice: The sky> >>> c = q.choice_set.create(choice_text='Just hacking again', votes=0) # Choice對象可經過API訪問和他們關聯的Question對象 >>> c.question <Question: What's up?> # 一樣的,Question對象也可經過API訪問關聯的Choice對象 >>> q.choice_set.all() <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]> >>> q.choice_set.count() 3 # API會自動進行連表操做,經過雙下劃線分割關係對象。連表操做能夠無限多級,一層一層的鏈接。 # 下面是查詢全部的Choices,它所對應的Question的發佈日期是今年。(重用了上面的current_year結果) >>> Choice.objects.filter(question__pub_date__year=current_year) <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]> # 使用delete方法刪除對象 >>> c = q.choice_set.filter(choice_text__startswith='Just hacking') >>> c.delete()
Django爲你提供了一個基於項目model建立的一個後臺管理站點admin。
這個界面只給站點管理員使用,並不對大衆開放。雖然admin的界面可能不是那麼美觀,功能不是那麼強大,內容不必定符合你的要求,
可是它是免費的、現成的,而且仍是可定製的,有完善的幫助文檔。
首先,咱們須要經過下面的命令,建立一個能夠登陸admin站點的用戶:
$ python manage.py createsuperuser
Email address: qianyi@123.com Password: Password (again): The password is too similar to the email address. Bypass password validation and create user anyway? [y/N]: n Password: Password (again): (0.000) INSERT INTO `auth_user` (`password`, `last_login`, `is_superuser`, `username`, `first_name`, `last_name`, `email`, `is_staff`, `is_active`, `date_joined`) VALUES ('pbkdf2_sha256$120000$hxqaIpS92d rd$eAOzMV+PAlgAmpWe32pUCCbnor4W1qw/Y7ygVwxdsrg=', NULL, 1, 'qianyi', '', '', 'qianyi@123.com', 1, 1, '2019-08-06 14:39:18.192940'); args=['pbkdf2_sha256$120000$hxqaIpS92drd$eAOzMV+PAlgAmpWe32pUCCbnor4W1q w/Y7ygVwxdsrg=', None, True, 'qianyi', '', '', 'qianyi@123.com', True, True, '2019-08-06 14:39:18.192940'] Superuser created successfully.
服務器啓動後,在瀏覽器訪問http://127.0.0.1:8000/admin/
。你就能看到admin的登錄界面了:
利用剛纔創建的帳戶,登錄admin,你將看到以下的界面:
當前只有兩個可編輯的內容:groups和users。它們是django.contrib.auth
模塊提供的身份認證框架。
如今還沒法看到投票應用,必須先在admin中進行註冊,告訴admin站點,請將polls的模型加入站點內,接受站點的管理。
打開polls/admin.py
文件,加入下面的內容:
from django.contrib import admin
from polls import models admin.site.register(models.Question) admin.site.register(models.Choice) # Register your models here.
點擊「Questions」,進入questions的修改列表頁面。這個頁面會顯示全部的數據庫內的questions對象,你能夠在這裏對它們進行修改。
看到下面的「What's new?」
了麼?它就是咱們先前建立的一個question對象,而且經過__str__
方法的幫助
這裏須要注意的是:
HTML input
框類型。DateTimeField
都會自動生成一個可點擊連接。日期是Today,並有一個日曆彈出框;時間是Now,並有一個通用的時間輸入列表框。
在頁面的底部,則是一些可選項按鈕:
delete
:彈出一個刪除確認頁面save and add another
:保存當前修改,並加載一個新的空白的當前類型對象的表單。save and continue editing
:保存當前修改,並從新加載該對象的編輯頁面。save
:保存修改,返回當前對象類型的列表頁面。在頁面的右上角,點擊History
按鈕,你會看到你對當前對象的全部修改操做都在這裏有記錄,包括修改時間和操做人員,以下圖所示:
一個視圖就是一個頁面,一般提供特定的功能,使用特定的模板。
打開polls/views.py
文件,輸入下列代碼:
def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] context = {'latest_question_list': latest_question_list} # render()函數的第一個位置參數是請求對象(就是view函數的第一個參數),第二個位置參數是模板。還能夠有一個可選的第三參數, # 一個字典,包含須要傳遞給模板的數據。最後render函數返回一個通過字典數據渲染過的模板封裝而成的HttpResponse對象。 return render(request, 'polls/index.html', context) def detail(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/detail.html', {'question': question}) def results(request, question_id): response = "You're looking at the results of question %s." return HttpResponse(response % question_id) def vote(request, question_id): return HttpResponse("You're voting on question %s." % question_id)
在polls/urls.py
文件中加入下面的url模式,將其映射到咱們上面新增的視圖
urlpatterns = [ path('', views.index, name='index'), # ex: /polls/5/ path('<int:question_id>/', views.detail, name='detail'), # ex: /polls/5/results/ path('<int:question_id>/results/', views.results, name='results'), # ex: /polls/5/vote/ path('<int:question_id>/vote/', views.vote, name='vote'), ]
快捷方式:get_object_or_404()
get_object_or_404()
方法將一個Django模型做爲第一個位置參數,後面能夠跟上任意個數的關鍵字參數,若是對象不存在則彈出Http404錯誤。
一樣,還有一個get_list_or_404()
方法,和上面的get_object_or_404()
相似,只不過是用來替代filter()
函數,當查詢列表爲空時彈出404錯誤。
(filter是模型API中用來過濾查詢結果的函數,它的結果是一個列表集。而get則是查詢一個結果的方法,和filter是一個和多個的區別!)
polls/templates/polls/index.html
:
{% if latest_question_list %} <ul> {% for question in latest_question_list %} <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> {% endfor %} </ul> {% else %} <p>No polls are available.</p> {% endif %}
polls/detail.html
<h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }}</li> {% endfor %} </ul>
在polls/index.html
文件中,還有一部分硬編碼存在,也就是href裏的「/polls/」部分:
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
設想若是你在urls.py文件裏修改了路由表達式,那麼你全部的模板中對這個url的引用都須要修改,這是沒法接受的!
使用前面給urls定義了一個name別名,能夠用它來解決這個問題。具體代碼以下
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
Django會在polls.urls
文件中查找name='detail'
的url,具體的就是下面這行:
path('<int:question_id>/', views.detail, name='detail'),
舉個栗子,若是你想將polls的detail視圖的URL更換爲polls/specifics/12/
,那麼你不須要在模板中從新修改url地址了,
僅僅只須要在polls/urls.py
文件中,將對應的正則表達式改爲下面這樣的就好了,全部模板中對它的引用都會自動修改爲新的連接:
# 添加新的單詞'specifics' path('specifics/<int:question_id>/', views.detail, name='detail'),
本教程例子中,只有一個app也就是polls,可是在現實中很顯然會有5個、10個、更多的app同時存在一個項目中。Django是如何區分這些app之間的URL name呢?
答案是使用URLconf的命名空間。在polls/urls.py文件的開頭部分,添加一個app_name
的變量來指定該應用的命名空間:
from django.urls import path from . import views app_name = 'polls' urlpatterns = [ path('', views.index, name='index'), # ex: /polls/5/ path('<int:question_id>/', views.detail, name='detail'), # ex: /polls/5/results/ path('<int:question_id>/results/', views.results, name='results'), # ex: /polls/5/vote/ path('<int:question_id>/vote/', views.vote, name='vote'), ]
如今,讓咱們將代碼修改得更嚴謹一點,將polls/templates/polls/index.html
中的
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
修改成
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>