一:Web投票示例
本節我們首先從全局范圍再復習一下Django的概念,讓自己對Django的設計理念, 功能模塊,體系架構,基本用法有初步的印象。
Django初始的詳細博客內容:請點擊我
該應用包括以下兩個部分:
- 一個可以讓公眾用戶進行投票和查看投票結果的站點
- 一個可以進行增刪改查的后台admin管理界面
在開始之前,我們可以查看安裝的Django是什么版本,在命令行輸入:
python -m django --version
1.1 新建項目
進入我們指定的項目保存目錄,然后運行下面的命令:
django-admin startproject mysite
這將在目錄下生成一個mysite目錄,也就是我們這個Django項目的根目錄。它包含了一系列自動生成的目錄和文件,具備各自專有的用途。
1.2 啟動開發服務器
進入mysite項目的根目錄,輸入下面的命令:
python manage.py runserver
你會看到下面的提示,這表明Django的開發
Django提供一個用於開發的web服務器,使你無需配置一個類似Ngnix的線上服務器,就能讓站點運行起來。這是一個由Python編寫的輕量級服務器,簡易並且不安全,因此不要將它用於生產環境。
打開瀏覽器,訪問http://127.0.0.1:8000/,你將看到Django的歡迎界面,一切OK!
Django的開發服務器(以后簡稱服務器)默認運行在內部的8000端口,如果你想指定端口,請在命令中顯示給出:
python manage.py runserver 8080
如果你想修改服務器的IP地址,請按以下方式運行命令:
python manage.py runserver 0.0.0.0:8000
這時,Django將運行在8000端口,整個局域網內都可以訪問站點,而不只是本機。
注意:Django的開發服務器具有自動重載功能,當你的代碼有修改,每隔一段時間服務器將自動更新。但是,有一些例如增加文件的動作,不會觸發服務器重載,這時候就需要你自己手動重啟。
1.3 創建投票APP
進入mysite項目根目錄,確保與,manage.py文件處於同一級,輸入下述命令:
python manage.py startapp polls
系統會自動生成polls應用的目錄,其結構如下:
polls/ __init__.py admin.py apps.py migrations/ __init__.py models.py tests.py views.py
1.4 編寫第一個視圖
在polls/views.py文件中,編寫代碼:
from django.http import HttpResponse def index(request): return HttpResponse("Hello, world. You're at the polls index.")
1.5 URL管理
- 1,創建好Project后再全局配置文件中有一個urls.py這個模型,該模型主要管理本項目的全局url配置
- 2,每個APP也應該創建一個urls.py模塊來管理自己APP下的url集
APP下的urls.py
為了調用該視圖,我們還需要編寫urlconf,也就是路由路徑。現在在polls目錄中新建一個文件,名字為url.py,在其中輸入代碼如下:
- 1,import django 中的url模塊
- 2,import app 中的views模塊
- 3,需要注意的是url時以正則表達式來配置管理,訪問web頁面的url = 全局url + APP url
from django.conf.urls import url from . import views urlpatterns = [ url(r'^$',views.index, name='index'), ]
此時,目錄的文件結構是這樣的:
polls/ __init__.py admin.py apps.py migrations/ __init__.py models.py tests.py urls.py views.py
全局urls.py配置
- 1,需要import include模塊
- 2,在urlpatterns中添加app下的urls模塊,namespace參數可以防止不同app下的url name
接下來,我們在項目的主urls文件中添加urlpattern條目,指向我們剛才建立的polls這個APP獨有的urls文件,這里需要導入include模塊,打開mysite/urls.py文件,代碼如下:
from django.conf.urls import include,url from django.contrib import admin urlpatterns = [ url(r'^polls/',include('polls.urls')), url(r'^admin/',admin.site.urls), ]
include語法相當於多級路由,它把接收到的url地址去除前面的正則表達式,將剩下的字符串傳遞給下一級路由進行判斷。
include的背后是一種即插即用的思想,項目根路由不關心具體APP的路由策略,只管往指定的二級路由轉發,實現了應用解耦。APP所屬的二級路由可以根據自己的需要隨意編寫,不會和其他的APP路由發生沖突。APP目錄可以放置在任何位置,而不用修改路由。這是轉件設計里很常見的一種模式。
建議:除了admin路由外,盡量給每個APP設計自己獨立的二級理由。
好了,路由設置成功后,啟動服務器,然后在瀏覽器中訪問地址http://localhost:8000/polls/
。一切正常的話,你將看到“Hello, world. You’re at the polls index.”
1.6 url方法
url()方法可以接受4個參數,其中2個是必須的:regex和view,以及2個可選的參數:kwargs和name。
regex
regex是正則表達式的通用縮寫,它是一種匹配字符串或者url地址的語法。Django拿着用戶請求的url地址,在url.py文件中對urlpatterns列表中的每一項條目從頭開始進行逐一對比,一旦遇到匹配項,立即執行該條目映射的視圖函數或者下級路由,其后的條目將不再繼續匹配。因此,url路由的編寫順序非常重要!
需要注意的是,regex不會去匹配GET和POST參數或者域名,例如對於https://www.example.com/myapp/,regex只嘗試匹配myapp/。對於https://www.example.com/myapp/?page=3,regex也只嘗試匹配myapp/。
當URLconf模塊加載的時候會預先編譯正則表達式,因此他的匹配搜索速度非常快,你通常感覺不到。
view
view指的是處理當前url請求的視圖函數,當正則表達式匹配到某個條目時,自動將封裝的HTTPRequest對象作為第一個參數,正則表達式“捕獲”到的值作為第二個參數,傳遞該條目指定的視圖view。如果是簡單捕獲,那么捕獲值將作為一個位置參數進行傳遞,如果是命名捕獲,那么將作為關鍵字參數進行傳遞。
kwargs
任意數量的關鍵字參數可以作為一個字典傳遞給目標視圖
name
對你的URL進行命名,讓你能夠在Django的任意處,尤其是模板內顯式的引用它,這是一個非常強大的功能,相當於給URL取了一個全局變量名。不會將url匹配地址寫死。
注意:
- 1,如果正則里面有()括號表示為分組,會自動將()括號里面的內容傳到views.article_page視圖中
- 2,如果正則格式為:(?P<>)表示為命名分組,在View視圖里面或者template調用的時候,可以直接使用命名去調用
在url.py中我們可以使用正則表達式來匹配url
urlpatterns = [ url(r'^$', views.index), url(r'^article/(?P<article_id>[0-9]+)$', views.article_page), ]
其中(?P<atricle>...)子串匹配到的內容將可以用命名的name來提取url的值,組的name必須是有效的Python標識符,而且在本表達式內不重名。
二,數據庫安裝
打開mysite/settings.py配置文件,這是整個Django項目的設置中心。Django默認使用SQLite數據庫,因為Python源生支持SQLite數據庫,所以我們無需安裝任何程序,就可以直接使用它。當然,如果你是在創建一個實際的項目,可以使用類似PistgreSQL的數據庫,避免以后數據庫遷移的相關問題。
# Database # https://docs.djangoproject.com/en/2.1/ref/settings/#databases DATABASES = { 'default': { # 這里可以指定使用的數據庫類型,例如mysql '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’)
,將把該文件儲存在你的項目目錄下。
如果不是使用默認的SQLite數據庫,那么一些諸如USER,PASSWORD和HOST的參數必須手動指定!下面給出一個基於pymysql操作MySQL數據庫的例子。
# mysite/settings.py # 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': 'mysite', 'HOST': '192.168.1.1', 'USER': 'root', 'PASSWORD': 'pwd', 'PORT': '3306', } }
注意:
- 在使用非SQLite的數據庫時,請務必預先在數據庫管理系統的提示符交互模式下創建數據庫,你可以使用命令:‘CREATE DATABASE database_name;’。Django不會自動幫你做這一步工作。
- 確保你在settings文件中提供的數據庫用戶具有創建數據庫表的權限,因為在接下來的教程中,我們需要自動創建一個test數據表(在實際項目中也需要確認這一條要求)
- 如果你使用的是SQLite,那么你無需做任何預先配置,直接使用即可。
修改時間
在修改settings文件時候,請順便將TIME_ZONE設置為國內所在的時間Asia/Shanghai。
INSTALLED_APPS設置項的了解
請注意settings文件中頂部的INSTALLED_APPS
設置項。它列出了所有的項目中被激活的Django應用(app)。你必須將你自定義的app注冊在這里。每個應用可以被多個項目使用,並且可以打包和分發給其他人在他們的項目中使用。
默認情況,INSTALLED_APPS
中會自動包含下列條目,它們都是Django自動生成的:
- django.contrib.admin:admin管理后台站點
- django.contrib.auth:身份認證系統
- django.contrib.contenttypes:內容類型框架
- django.contrib.sessions:會話框架
- django.contrib.messages:消息框架
- django.contrib.staticfiles:靜態文件管理框架
上面的一些應用也需要建立一些數據庫表,所以在使用它們之前我們要在數據庫中創建這些表。使用下面的命令創建數據表:
Python manage.py migrate
migrate命令將遍歷INSTALLED_APPS設置中的所有項目,在數據庫中創建對應的表,並打印出每一條動作信息,如果你感興趣,可以在你的數據庫命令行下輸入:\dt (PostgreSQL),SHOW TABLES;或者.schema(SQLite)來列出Django所創建的表。
三,創建模型
現在我們來定義模型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文件,具體代碼如下:
# 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的子類。每一個字段都是Filed類的一個實例,例如用於保存字符數據的CharFiled和用於保存時間類型的DateTimeFiled,它部門告訴Django每一個字段保存的數據類型。
每一個Field實例的名字就是字段的名字(如:question_test或者pub_date)。在你的Python代碼中會使用這個值,你的數據庫也會將這個值作為表的列名。
你也可以在每個Field中使用一個可選的第一位置參數用於提供一個人類可讀的字段名,讓你的模型更友好,更易讀,並且將被作為文檔的一部分來增強代碼的可讀性。
一些Field類必須提供某些特定的參數,例如CharField需要你指定max_length,這不僅是數據庫結構的需要,同樣也用於數據驗證功能。
有必填參數,當然就會有可選參數,比如在votes里我們將其默認值設置為0。
最后請注意,我們使用ForeignKey定義了一個外鍵關系。它告訴Django,每一個Choice關聯到一個對應的Question(注意要將外鍵寫在‘多’的一方)。Django支持通用的數據關系:一對一,多對一和多對多。
四,啟用模型
上面的代碼看着有點少,其實包含了大量的信息,據此,Django會做下面兩件事情:
- 創建該APP對應的數據庫表結構
- 為Question和Choice對象創建基於Python的數據庫訪問API
但是,我們必須首先告訴Django項目,我們要使用投票APP。
要將應用添加到項目中,需要在INSTALLED_APPS設置中增加指向該應用的配置文件的鏈接。對於本例的投票應用,它的配置類文件是polls/apps.py,路徑格式為polls.apps.PollsConfig。我們需要在INSTALLED_APPS中,將該路徑添加進去:
# mysite/settings.py INSTALLED_APPS = [ 'polls.apps.PollsConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ]
實際上,在多數情況下,我們簡寫成‘polls’就可以了;
# mysite/settings.py INSTALLED_APPS = [ 'polls', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ]
現在Django已經知道你的投票應用的存在了,並把它加入了項目大家庭。
我們需要再運行一下命令:
python manage.py makemigrations polls
你會看到類似下面的提示:
通過運行makemigrations命令,相當於告訴Django你對模型有改動,並且你想把這些改動保存為一個“遷移(migration)”。
migration 是Django保存模型修改記錄的文件,這些文件保存在磁盤上。在例子中,它就是polls/migrations/0001_initial.py,你可以打開它看看,里面保存的都是人類可讀並且可編輯的內容,方便你隨時手動修改。
接下來有一個叫做migrate的命令將對數據庫執行真正的遷移動作。但是在此之前,讓我們先看看在migration的時候實際執行的SQL語句是什么。有一個叫做sqlmigrate的命令可以展示SQL語句,例如:
python manage.py sqlmigrate polls 0001
你將會看到如下類似的文本(經過適當的格式調整,方便閱讀)
BEGIN; -- -- Create model Choice -- CREATE TABLE "polls_choice" ( "id" serial NOT NULL PRIMARY KEY, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL ); -- -- Create model Question -- CREATE TABLE "polls_question" ( "id" serial NOT NULL PRIMARY KEY, "question_text" varchar(200) NOT NULL, "pub_date" timestamp with time zone NOT NULL ); -- -- Add field question to choice -- ALTER TABLE "polls_choice" ADD COLUMN "question_id" integer NOT NULL; ALTER TABLE "polls_choice" ALTER COLUMN "question_id" DROP DEFAULT; CREATE INDEX "polls_choice_7aa0f6ee" ON "polls_choice" ("question_id"); ALTER TABLE "polls_choice" ADD CONSTRAINT "polls_choice_question_id_246c99a640fbbd72_fk_polls_question_id" FOREIGN KEY ("question_id") REFERENCES "polls_question" ("id") DEFERRABLE INITIALLY DEFERRED; COMMIT;
請注意:
- 實際的輸出內容將取決於您使用的數據庫會有所不同,上面的是PostgreSQL的輸出。
- 表名是自動生成的,通過組合應用名(polls)和小寫的模型名question和choice。(這兩個模型名稱是我們自己建立的,你也可以自己建立)
- 主鍵(IDs)是自動添加的(我們也可以重寫此行為)
- 按照慣例,Django會在外鍵字段名稱上附加“_id” (我們也可以重寫此行為)
- 生成的SQL語句時針對你所使用的數據庫,會為你自動處理特定於數據庫的字段,例如anto_increment(MySQL),serial(PostgreSQL),或者integer primary key(SQLite),在引用字段名時也是如此,比如使用雙引號護着單引號。
- 這些SQL命令並沒有在你的數據庫中實際運行,它只是在屏幕上顯示出來,以便讓你了解Django真正執行的是什么
如果你干星期,也可以運行下面命令,它將檢查項目中的錯誤,並不實際進行遷移或者鏈接數據庫的操作。
python manage.py check
現在我們可以運行migrate命令,在數據庫中進行真正的表操作了。
migrate命令對所有還未實施的遷移記錄進行操作,本質上就是將你對模型的修改體現到數據庫中具體的表上面。
Django通過一個叫做Django_migrations的表,記錄並跟蹤已經實施的migrate動作,通過對比獲得哪些migrations尚未提交。
migrations的功能非常強大,允許你隨機修改你的模型,而不需要刪除或者新建你的數據庫或者數據表,在不丟失數據的同時,實時動態更新數據庫,我們將在后面的章節對此進行深入的闡述,但是現在,只需要記住修改模型時的操作分為三步:
- 在models.py中修改模型
- 運行 python manage.py makemigrations 為改動創建遷移記錄
- 運行 python manage.py migrate ,將操作同步到數據庫
之所以要將創建和實時遷移的動作分成兩個命令兩步走是因為你也許要通過版本控制系統(例如GitHub SVN)提交你的項目代碼,如果沒有一個中間過程的保存文件(migrations),那么GitHub如何知道以及記錄,同步,實施你所進行過的模型修改動作呢?畢竟,GitHub不和數據庫直接打交道,也沒法和你本地的數據通信。但是分開之后。你只需要將你的migrate文件(例如上面的0001)上傳到GitHub,它就知道一切。
五,使用模型的API
下面,讓我們進入Python的交互環境,嘗試使用Django提供的數據庫訪問API,要進入Python的shell,請輸入命令:
python manage.py shell
相比較直接輸入“Python”命令的方式進入Python環境,調用manage.py參數能將DJANGO_SETTINGS_MODULE 環境變量導入,它將自動按照mysite/settings.py中的設置,配置好你的Python shell環境,這樣你就可以導入和調用你項目內的模塊了。
或者你也可以這樣,先進入一個純凈的Python shell環境,然后啟動Django,具體如下:
>>> import django >>> django.setup()
當你進入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 from django.utils.encoding import python_2_unicode_compatible @python_2_unicode_compatible # 當你想支持python2版本的時候才需要這個裝飾器 class Question(models.Model): # ... def __str__(self): # 在python2版本中使用的是__unique__ return self.question_text @python_2_unicode_compatible class Choice(models.Model): # ... def __str__(self): return self.choice_text
這個技巧,不但對我們打印對象時很有幫助,在我們使用Django的admin站點時也同樣有幫助。
另外,這里我們自定義一個模型的方法,用於判斷問卷是否最近時間段內發布的。
import datetime from django.db import models from django.utils import timezone class Question(models.Model): # ... def was_published_recently(self): return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
請注意上面分別導入了兩個關於時間的模塊,一個是Python內置的datatime模塊,一個是Django工具包提供的timezone模塊。
保存修改后,我們重新啟動一個新的Python shell ,再來看看其他的API。
>>> 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項目的核心,也會動態網站與數據庫交互的核心。
六,admin后台管理站點
很多時候,我們不光要開發針對客戶使用的前端頁面,還要給后台管理人員提供相應的管理界面。但是大多數時候為你的團隊或者客戶編寫用於增加,修改和刪除內容的后台管理站點是一件非常乏味的工作並且沒有多少創造性,而且也需要花費不少的時間和精力。Django最大的優點之一就是體貼的為你提供了一個基於項目model創建的一個后台管理站點admin。這個界面只給站點管理員使用,並不對大眾開放,雖然admin的界面可能不是那么美觀,功能不是那么強大,內容不一定符合你的要求,但是它是免費的,現成的,並且還是可制定的,有完善的幫助文檔,所以。。
1,創建管理員用戶
首先,我們需要通過下面的命令,創建一個可以登錄的admin站點的用戶:
python manage.py createsuperuser
輸入用戶名:
Username: admin
輸入郵箱地址:
Email address: xxx@xxx.xxx
輸入密碼:
Password: ********** Password (again): ********* Superuser created successfully.
注意:Django1.10版本后,超級用戶的密碼強制要求有一定的復雜性。
2,啟動開發服務器
服務器啟動后,在瀏覽器訪問http://127.0.0.1:8000/admin/。我們就能看到admin的登錄界面了:
在實際環境中,為了站點的安全性,我們不能將管理后台的url隨便暴露給他人,不能用/admin/這么簡單的路徑。
打開跟url路由文件mysite/url.py,修改其中admin.site.urls對應的正則表達式,比如:
from django.conf.urls import url from django.contrib import admin urlpatterns = [ url(r'^my/set/', admin.site.urls), ]
這樣,我們必須訪問http://127.0.0.1:8000/my/set/
才能進入admin界面。
3,進入admin站點
利用剛才建立的admin賬戶,登錄admin,你將看到如下的界面:
當前只有兩個可編輯的的內容,groups和users,他們是django.contrib.auth模塊提供的身份認證框架。
4,在admin中注冊投票應用
現在還無法看到投票應用,必須先在admin中注冊,告訴admin站點,請將polls的模型加入站點內,接受站點的管理。
打開polls.admin.py文件,加入下面的內容:
from django.contrib import admin from .models import Question admin.site.register(Question)
5,admin的站點的主要功能
注冊question模型后,刷新admin頁面就能看到Question欄目了。
點擊“Question”,進入questions的修改列表頁面。這個頁面會顯示所有的數據庫內的questions對象,你可以在這里對他們進行修改,看到下面的“what 's up?”了嗎?它就是我們之前創建的一個question對象,並且通過__str__方法的幫助,顯示了較為直觀的信息,而不是一個冷冷的對象類型名稱。
下面點擊 what's up ? 進入編輯頁面:
這里需要注意的是:
- 頁面中的表單是由Question模型自動生成的
- 不同的模型字段類型(DateTimeField , CharField)會表現為不同的HTML input 框類型。
- 每一個DateTimeField都會自動生成一個可點擊鏈接,日期是Today,並且有一個日歷彈出框;時間是Now,並且有一個通用的時間輸入列表框。
在頁面的底部,則是一些可選項按鈕:
- delete 彈出一個刪除確認頁面
- save and add another : 保存當前修改,並加載一個新的空白的當前類型對象的表單
- save and continue aditing :保存當前修改,並重新加載該對象的編輯頁面
- save :保存修改,返回當前對象類型的列表頁面
如果Date published字段的值和你在前面創建它的時候不一致,可能你沒有正確的配置TIME_ZONE ,在國內,通常是8個小時的時間差別。修改TIME_ZONE 配置並重新加載頁面,就能顯示正確的時間了。
在頁面的右上角,點擊History按鈕,你會看到你對當前對象的所有修改操作都在這有記錄,包括修改時間和操作人員,如下圖所示:
6,admin后台管理用戶密碼修改
方法一
在Terminal中執行下面代碼:
python manage.py changepassword your_name
(其中“your_name”為你要修改密碼的用戶名),根據提示內容修改即可。
方法二
進入shell環境,執行:
from django.contrib.auth.models import User u = User.objects.get(username='your_name') u.set_password('new_password') u.save()
7,定制admin整體界面
很明顯,在每一個項目的admin頁面頂端都顯示Django administration是很可笑的,它僅僅是個占位文本。利用Django的模板系統,我們可以快速的修改它。
7.1 定制項目模板
在manage.py文件同級下創建一個templates目錄,然后打開設置文件mysite/settings.py 。在TEMPLATES條目中添加一個DIRS選項。
# mysite/settings.py TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], # 要有這一行,如果已經存在請保持原樣 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
DIRS是一個文件系統目錄的列表,是模板的搜索路徑。當加載Django模板的時候,會在DIRS中進行查找。
7.2 模板的組織方式
就像靜態文件一樣,我們可以把所有的模板都放在一起,形成一個大大的模板文件夾,並且工作正常。但請一定不要這樣做,強烈建議每一個模板都應該存在它所屬應用的模板目錄內(例如polls/templates)而不是整個項目的模板目錄(tenplates),因為這樣每個應用才可以被方便和正確的重要。只有對整個項目有作用的模板文件才放在根目錄的templates中,比如admin界面。
回到剛才創建的templates目錄下,再創建一個admin目錄,將admin/base_site.html模板文件拷貝到該目錄內。這個HTML文件來自Django源碼。他位於django/contrib/admin/templates目錄內。
在Windows系統中,位於此:
C:\Python36\Lib\site-packages\django\contrib\admin\templates\admin
如果你無法找到Django源代碼文件的存放位置,可以使用下面的命令:
python -c "import django; print(django.__path__)"
編輯base_site.html 文件,用你喜歡的站點名字替換掉下面代碼
{{ site_header|default:_(’Django administration’) }}
包括兩個大括號一起替換掉,看起來像下面這樣:
{% extends "admin/base.html" %} {% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %} {% block branding %} <h1 id="site-name"><a href="{% url 'admin:index' %}">投票站點管理界面</a></h1> {% endblock %} {% block nav-global %}{% endblock %}
在這里,我們使用的是硬編碼,強行改為“投票站點管理界面”。但是在實際的項目中,你可以使用下面屬性,方便的對這個頁面title進行自定義。
django.contrib.admin.AdminSite.site_header
修改完后,刷新頁面,效果如下:
提示:所有Django默認的admin模板都可以被重寫,類似剛才重寫base_site.html
模板的方法一樣,從源代碼目錄將HTML文件拷貝至你自定義的目錄內,然后修改文件。
8,定制admin首頁
默認情況下,admin首頁顯示所有INSTALLED_APPS內並在admin應用中注冊過的APP,以字母順序進行排序。
要定制admin首頁,你需要重寫admin/index.html模板,就像前面修改base_site.html模板的方法一樣,從源碼目錄拷貝到你指定的目錄內。編輯該文件,你會看到文件內使用了一個app_list模板變量,該變量包含了所有已經安裝的Django應用,你可以硬編碼鏈接到指定對象的admin頁面,使用任意你覺得OK的方法,用於替代這個app_list。
七,視圖的學習
1,視圖概述
一個視圖就是一個頁面,通常提供特定的功能,使用特定的模板。例如:在一個博客應用中,你可能會看到下列視圖:
- 博客主頁:顯示最新發布的一些內容
- 每篇博客的詳細頁面:博客的永久鏈接
- 基於年的博客頁面:顯示指定年內的所有博客
- 基於月的博客頁面:顯示指定月內的所有博客
- 基於日的博客頁面:顯示指定日內的所有博客
- 發布評論:處理針對某篇博客發布的評論
在我們的投票應用中,我們將建立下面的視圖:
- 問卷“index”頁:顯示最新的一些問卷
- 問卷“detail”頁面:顯示一個問卷的詳細文本內容,沒有調查結果但是有一個投票或調查表單。
- 問卷“results”頁面:顯示某個問卷的投票或調查結果。
- 投票動作頁面:處理針對某個問卷的某個選項的投票動作。
在Django中,網頁和其他的一些內容都是通過視圖來處理的,視圖其實就是一個簡單的Python函數(在基於類的視圖中稱為方法)。Django通過對比請求的URL地址來選擇對應的視圖。
2,編寫視圖
下面,打開polls.view.py文件,輸入下列代碼:
def detail(request,qiestion_id): return HttpResponse("you are lokking at quetion %s."%question_id) def results(request,question_id): respose = "You're looking at the results of question %s." return HttpResponse(respose % question_id) def vote(request,question_id): return HttpResponse("You're voting on question %s."%question_id)
然后在polls/urls.py文件中加入下面的url模式,將其映射到我們上面新增的視圖。
urlpatterns = [ # url(r'^polls/',include('polls.urls')), # ex :/polls/ url(r'^$',views.index, name='index'), # ex :/polls/5/results/ url(r'^(?P<question_id>[0-9]+)/$',views.detail,name='detail'), # ex:/polls/5/results/ url(r'^(?P<question_id>[0-9]+)/results/$',views.results,name='results'), # ex: /polls/5/vote url(r'^(P<question_id>[0-9]+)/vote/$',views.vote,name='vote'), ]
現在去瀏覽器中訪問/polls/34/
(注意:這里省略了域名。另外,使用了二級路由后,url中都要添加polls部分,參考前面的章節),它將調用detail()
函數,然后在頁面中顯示你在url里提供的ID。訪問/polls/34/results/
和/polls/34/vote/
,將分別顯示預定義的偽結果和投票頁面。
上面訪問的路由過程如下:當有人訪問/polls/34/
地址時,Django將首先加載mysite.urls
模塊,因為它是settings文件里設置的根URL配置文件。在該文件里,Django發現了urlpatterns
變量,於是在其內按順序進行匹配。當它匹配上了^polls/
,就裁去url中匹配的文本polls/
,然后將剩下的文本“34/”,傳遞給polls.urls
進行下一步的處理。在polls.urls
中,又匹配到了r’^(?P<question_id>[0-9]+)/$’
,最終結果就是調用該模式對應的detail()視圖,也就是下面的函數:
detail(request=<HttpRequest object>, question_id='34')
函數中的question_id=’34’
參數,是由(?P<question_id>[0-9]+)
而來。在正則表達式中通過一個雙圓括號,Django會捕獲它匹配到的值並傳遞給對應的視圖,作為視圖的位置參數之一,而?P<question_id>
則表示我要給這個捕獲的值指定一個特殊的變量名,在視圖中可以通過question_id
這個變量名隨意的引用它,形成一個關鍵字參數,不用考慮參數的位置。至於[0-9]+
則是一個很簡單的原生正則表達式,用於匹配一系列連續的數字,它匹配到的值也就是具體要傳遞的參數值。
所有的URL模式都是正則表達式,Django不限制你在url模式中的書寫方式。但是,你真的沒必要書寫一個如下的較為愚蠢的包含.html
的模式,它顯然是沒必要,不夠簡練的:
url(r'^polls/latest\.html$', views.index),
你完全可以用下面的模式代替上面的:
url(r'^polls/latest$', views.index),
3,寫一個實際的視圖
每一個視圖至少做兩件事之一:返回一個包含請求頁面的HTTPResponse對象或者彈出一個類似Http404的異常,其他的則隨便你,你愛干什么干什么。
下面是一個Http404異常界面:
下面是一個新的index()視圖,用於替代先前無用的index。它會根據發布日期顯示最近的5個投票問卷。
from django.http import HttpResponse from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] output = ', '.join([q.question_text for q in latest_question_list]) return HttpResponse(output) # 下面是那些沒改動過的視圖(detail, results, vote)
這里有一個非常重要的問題:在當前視圖中的HTML頁面是硬編碼的。如果你想改變頁面的顯示內容,就必須修改這里的Python代碼。為了解決這個問題,需要使用Django提供的模板系統,解耦視圖和模板之間的硬鏈接。
首先,在polls目錄下創建一個新的templates目錄,Django會在它里面查找模板文件。在templates目錄中,再創建一個新的子目錄叫polls,進入該子目錄,創建一個新的index.html。換句話說你的模板文件應該是polls/template/polls/index.html。可以在Django中直接使用polls/index/html引用該文件。
注意:在Pycharm中,templates文件夾通常已經幫你創建好了!
模板命名空間
你也許會想,為什么不把模板文件直接放在polls/templates目錄下,而是費勁的再建一個子目錄呢?設想這么個情況,有另外一個APP,它也有一個名為Index.html的文件,當Django在搜索模板時,有可能找到它,然后退出搜索,這就命中了錯誤的目錄,不是我們想要的結果。解決了這個問題的最好辦法就是在templates目錄下再建立一個與APP同名的子目錄,將自己所屬的模板都放在里面,從而達到 獨立命名空間的作用,不會再出現引用錯誤。
現在,將下面代碼寫入文件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/views.py,讓新的index.html文件生效。
from django.http import HttpResponse from django.template import loader from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] template = loader.get_template('polls/index.html') context = { 'latest_question_list': latest_question_list, } return HttpResponse(template.render(context, request))
上面的代碼會加載polls/index.html文件,並傳遞給它一個參數,這個參數是一個字典,包含了模板變量名和Python對象之間的映射關系。
在瀏覽器中通過訪問/polls/,你可以看到一個列表,包含“what's up” 的問卷,以及連接到其對應詳細內容頁面的鏈接點。
如果你顯示的是下面的頁面,說明你前面沒有添加Question對象。沒關系,我們可以手動添加以下即可。
進入admin界面,選擇Questions,點擊右上角的Add question,如下操作。
快捷方式:render()
在實際運用中,加載模板,傳遞參數,返回HTTPResponse對象時一整套再常用不過的操作了,為了節省力氣,Django提供了一個快捷方式,render函數,一步到位,看如下代碼:
polls/views.py
from django.shortcuts import render from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] context = {'latest_question_list': latest_question_list} return render(request, 'polls/index.html', context)
render()函數的第一個位置參數是請求對象(就是view函數的第一個參數),第二個位置參數是模板,還可以有一個可選擇的第三參數,一個字典,包含需要傳遞給模板的數據,最后render函數返回一個經過字典數據渲染過的模板封裝而成的HTTPResponse對象。
HTTPResponse對象
對於HTTPRequest對象來說,是由Django自動創建的,但是HttpResponse對象就必須由我們自己創建,每個view請求處理方法必須返回一個HTTPResponse對象。
HTTPResponse類在Django.http.HttpResponse
在HTTPResponse對象上擴展的常用方法:
- 頁面渲染:render()
- 頁面跳轉:redirect(" path")
- locals() :可以直接將函數中所有的變量傳給模板
總結:render和redirect的區別
1,if render的頁面需要模板語言渲染,需要的將數據庫的數據加載到HTML,那么所有的這一部分除了寫在視圖函數中,必須還要寫在login中,沒有解耦。
2,render是渲染變量到模板中,而redirect是HTTP中的1個跳轉的函數,一般會生成302狀態碼。
4,返回404錯誤
現在讓我們來編寫具體問卷文本內容的視圖polls/views.py
from django.http import Http404 from django.shortcuts import render from .models import Question # ... def detail(request, question_id): try: question = Question.objects.get(pk=question_id) except Question.DoesNotExist: raise Http404("Question does not exist") return render(request, 'polls/detail.html', {'question': question})
所以,訪問的話,如果請求的問卷ID不存在,那么會彈出一個Http404錯誤。
新建polls/detail.html文件,暫時寫入下面的代碼:
{{ question }}
快捷方式:get_object_or_404()
就像render函數一樣,Django同樣為你提供了一個偷懶的方式,替代上面的多行代碼,那就是get_object_or_404()
方法,參考下面的代碼:
polls/view.py
from django.shortcuts import get_object_or_404, render from .models import Question # ... def detail(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/detail.html', {'question': question})
別說我沒提醒你,和render一樣,也需要從Django內置的快捷方式模塊中導出get_object_or_404()
!
get_object_or_404()
方法將一個Django模型作為第一個位置參數,后面可以跟上任意個數的關鍵字參數,如果對象不存在則彈出Http404錯誤。
同樣,還有一個get_list_or_404()
方法,和上面的get_object_or_404()
類似,只不過是用來替代filter()
函數,當查詢列表為空時彈出404錯誤。(filter是模型API中用來過濾查詢結果的函數,它的結果是一個列表集。而get則是查詢一個結果的方法,和filter是一個和多個的區別!)
5,模板的學習
detail()視圖會將上下文變量question傳遞給對應的polls/templates/polls/detail/html 模板,修改該模板的內容,如下所示:
<h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }}</li> {% endfor %} </ul>
在模板系統中 圓點. 是萬能的魔法師,你可以用它訪問對象的屬性,在例子{{question.question_text }} 中,Django首先會在Question對象中嘗試查找一個字典,如果失敗,則嘗試查找屬性,如果再失敗,則嘗試作為列表的索引進行查詢。
在{ % for %} 循環中的方法調用——poll.choice_set.all其實就是Python的代碼poll.choice_set.all() ,它將返回一組可迭代的Choice對象,並用在{& for %}標簽中。
這里我們對Django模板語言有個簡單的印象就好。
6,刪除模板中硬編碼的URLs
在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,具體的就是下面這行:
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
舉個例子,如果你想要將polls的detail視圖的URL更換為polls.specifices/12/,那么你不需要在模板中重新修改url地址了,僅僅只需要在polls/urls.py文件中,將對應的正則表達式改成下面這樣的就好了,所有模板中對它的引用都會自動修改成新的鏈接:
# 添加新的單詞'specifics' url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
7,URL names的命名空間
在本文中,只有一個APP也就是polls,但是在現實中很顯然會有5個,10個,更多的app同時在一個項目中。Django是如何區分這些APP之間的URL name呢?
使用URLconf的命名空間,在polls.urls.py文件的開頭部分,添加一個app_name的變量來指定該應用的命名空間:
from django.conf.urls import url from . import views app_name = 'polls' # 關鍵是這行 urlpatterns = [ url(r'^$', views.index, name='index'), url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'), url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'), url(r'^(?P<question_id>[0-9]+)/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>
注意引用方法是冒號而不是原點也不是斜杠!!!
8,視圖函數
一個視圖函數,簡稱視圖,是一個簡單的Python函數,它接受Web請求並且返回Web響應。響應可以是一張網頁的HTML內容,一個重定向,一個404錯誤,一個XML文檔,或者一張圖片....是任何東西都可以。無論視圖本身包含什么邏輯,都要返回響應。為了將代碼放在某處,約定是將視圖方式在項目或者應用程序目錄中的名為view.py的文件中。下面是一個返回當前日期和時間作為HTML文檔的視圖:
from django.shortcuts import render, HttpResponse, HttpResponseRedirect, redirect import datetime def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
讓我們逐行解析上面代碼:
1,首先,我們從django.shortcuts導入了HttpRespons類,以及Python的datetime庫。
2,我們定義了current_datetime函數,它就是視圖函數。每個視圖函數都使用HttpRequest對象作為第一個參數,並且通常稱之為request。
(注意:視圖函數的名稱並不重要;不需要用一個統一的命名方式來命名,以便讓Django識別它,我們將其命名為current_datetime,是因為這個名稱能夠精准地反映出它的功能)。
3,這個視圖會返回一個HttpResponse對象,其中包含生成的響應。每個視圖函數都負責返回一個HTTPResponse對象。
詳細可參考下圖:
所以視圖層,熟練掌握兩個對象即可:請求對象(request)和響應對象(HttpResponse)
HTTPRequest對象
request屬性,Django將請求報文中的請求行,首部信息,內容主體封裝成HttpRequest類中的屬性。除了特殊說明之外,其他均為只讀的。
1.HttpRequest.GET 一個類似於字典的對象,包含 HTTP GET 的所有參數。詳情請參考 QueryDict 對象。 2.HttpRequest.POST 一個類似於字典的對象,如果請求中包含表單數據,則將這些數據封裝成 QueryDict 對象。 POST 請求可以帶有空的 POST 字典 —— 如果通過 HTTP POST 方法發送一個表單,但是 表單中沒有任何的數據,QueryDict 對象依然會被創建。 因此,不應該使用 if request.POST 來檢查使用的是否是POST 方法;應該使用 if request.method == "POST" 另外:如果使用 POST 上傳文件的話,文件信息將包含在 FILES 屬性中。 注意:鍵值對的值是多個的時候,比如checkbox類型的input標簽,select標簽,需要用: request.POST.getlist("hobby") 3.HttpRequest.body 一個字符串,代表請求報文的主體。在處理非 HTTP 形式的報文時非常有用,例如: 二進制圖片、XML,Json等。 但是,如果要處理表單數據的時候,推薦還是使用 HttpRequest.POST 。 4.HttpRequest.path 一個字符串,表示請求的路徑組件(不含域名)。 例如:"/music/bands/the_beatles/" 5.HttpRequest.method 一個字符串,表示請求使用的HTTP 方法。必須使用大寫。 例如:"GET"、"POST" 6.HttpRequest.encoding 一個字符串,表示提交的數據的編碼方式(如果為 None 則表示使用 DEFAULT_CHARSET 的設置,默認為 'utf-8')。 這個屬性是可寫的,你可以修改它來修改訪問表單數據使用的編碼。 接下來對屬性的任何訪問(例如從 GET 或 POST 中讀取數據)將使用新的 encoding 值。 如果你知道表單數據的編碼不是 DEFAULT_CHARSET ,則使用它。 7.HttpRequest.META 一個標准的Python 字典,包含所有的HTTP 首部。具體的頭部信息取決於客戶端和服務 器,下面是一些示例: CONTENT_LENGTH —— 請求的正文的長度(是一個字符串)。 CONTENT_TYPE —— 請求的正文的MIME 類型。 HTTP_ACCEPT —— 響應可接收的Content-Type。 HTTP_ACCEPT_ENCODING —— 響應可接收的編碼。 HTTP_ACCEPT_LANGUAGE —— 響應可接收的語言。 HTTP_HOST —— 客服端發送的HTTP Host 頭部。 HTTP_REFERER —— Referring 頁面。 HTTP_USER_AGENT —— 客戶端的user-agent 字符串。 QUERY_STRING —— 單個字符串形式的查詢字符串(未解析過的形式)。 REMOTE_ADDR —— 客戶端的IP 地址。 REMOTE_HOST —— 客戶端的主機名。 REMOTE_USER —— 服務器認證后的用戶。 REQUEST_METHOD —— 一個字符串,例如"GET" 或"POST"。 SERVER_NAME —— 服務器的主機名。 SERVER_PORT —— 服務器的端口(是一個字符串)。 從上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,請求中的任何 HTTP 首部轉換為 META 的鍵時, 都會將所有字母大寫並將連接符替換為下划線最后加上 HTTP_ 前綴。 所以,一個叫做 X-Bender 的頭部將轉換成 META 中的 HTTP_X_BENDER 鍵。 8.HttpRequest.FILES 一個類似於字典的對象,包含所有的上傳文件信息。 FILES 中的每個鍵為<input type="file" name="" /> 中的name,值則為對應的數據。 注意,FILES 只有在請求的方法為POST 且提交的<form> 帶有enctype="multipart/form-data" 的情況下才會包含數據。否則,FILES 將為一個空的類似於字典的對象。 9.HttpRequest.COOKIES 一個標准的Python 字典,包含所有的cookie。鍵和值都為字符串。 10.HttpRequest.session 一個既可讀又可寫的類似於字典的對象,表示當前的會話。只有當Django 啟用會話的支持時才可用。 完整的細節參見會話的文檔。 11.HttpRequest.user(用戶認證組件下使用) 一個 AUTH_USER_MODEL 類型的對象,表示當前登錄的用戶。 如果用戶當前沒有登錄,user 將設置為 django.contrib.auth.models.AnonymousUser 的一個實例。你可以通過 is_authenticated() 區分它們。 例如: if request.user.is_authenticated(): # Do something for logged-in users. else: # Do something for anonymous users. user 只有當Django 啟用 AuthenticationMiddleware 中間件時才可用。 ------------------------------------------------------------------------------------- 匿名用戶 class models.AnonymousUser django.contrib.auth.models.AnonymousUser 類實現了django.contrib.auth.models.User 接口,但具有下面幾個不同點: id 永遠為None。 username 永遠為空字符串。 get_username() 永遠返回空字符串。 is_staff 和 is_superuser 永遠為False。 is_active 永遠為 False。 groups 和 user_permissions 永遠為空。 is_anonymous() 返回True 而不是False。 is_authenticated() 返回False 而不是True。 set_password()、check_password()、save() 和delete() 引發 NotImplementedError。 New in Django 1.8: 新增 AnonymousUser.get_username() 以更好地模擬 django.contrib.auth.models.User。
request常用方法
1.HttpRequest.get_full_path() 返回 path,如果可以將加上查詢字符串。 例如:"/music/bands/the_beatles/?print=true" 2.HttpRequest.is_ajax() 如果請求是通過XMLHttpRequest 發起的,則返回True,方法是檢查 HTTP_X_REQUESTED_WITH 相應的首部是否是字符串'XMLHttpRequest'。 大部分現代的 JavaScript 庫都會發送這個頭部。如果你編寫自己的 XMLHttpRequest 調用(在瀏覽器端),你必須手工設置這個值來讓 is_ajax() 可以工作。 如果一個響應需要根據請求是否是通過AJAX 發起的,並且你正在使用某種形式的緩存例 如Django 的 cache middleware, 你應該使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 裝飾你的視圖以讓響應 能夠正確地緩存。
HTTPResponse對象
響應對象主要有三種形式:
- 1,HttpResponse()
- 2,render()
- 3,redirect()
HttpResponse()括號內直接跟一個具體的字符串作為響應體,比較直接很簡單,所以這里介紹后面兩種
render()
render(request, template_name[, context]) 結合一個給定的模板和一個給定的上下文字典,並返回一個渲染后的 HttpResponse 對象。
參數:
- request: 用於生成響應的請求對象。
- template_name:要使用的模板的完整名稱,可選的參數
- context:添加到模板上下文的一個字典。默認是一個空字典。如果字典中的某個值是可調用的,視圖將在渲染模板之前調用它。
- render方法就是將一個模板頁面中的模板語法進行渲染,最終渲染成一個html頁面作為響應體。
redirect()
傳遞要重定向的一個硬編碼的URL
def my_view(request): ... return redirect('/some/url/')
也可以是一個完整的URL:
def my_view(request): ... return redirect('http://example.com/')
key:兩次請求
1)301和302的區別。 301和302狀態碼都表示重定向,就是說瀏覽器在拿到服務器返回的這個狀態碼后 會自動跳轉到一個新的URL地址,這個地址可以從響應的Location首部中獲取 (用戶看到的效果就是他輸入的地址A瞬間變成了另一個地址B)——這是它們的共同點。 他們的不同在於。301表示舊地址A的資源已經被永久地移除了(這個資源不可訪問了), 搜索引擎在抓取新內容的同時也將舊的網址交換為重定向之后的網址; 302表示舊地址A的資源還在(仍然可以訪問),這個重定向只是臨時地從舊地址A跳轉 到地址B,搜索引擎會抓取新的內容而保存舊的網址。 SEO302好於301 2)重定向原因: (1)網站調整(如改變網頁目錄結構); (2)網頁被移到一個新地址; (3)網頁擴展名改變(如應用需要把.php改成.Html或.shtml)。 這種情況下,如果不做重定向,則用戶收藏夾或搜索引擎數據庫中舊地址只能讓訪問 客戶得到一個404頁面錯誤信息,訪問流量白白喪失;再者某些注冊了多個域名的網站,也 需要通過重定向讓訪問這些域名的用戶自動跳轉到主站點等。
參考文獻:https://www.cnblogs.com/feixuelove1009/p/8404011.html
(在此主要是學習別人的經驗,整理自己的筆記,不喜勿噴,謝謝合作)