現(xiàn)在,打開 ?mysite/settings.py
? 。這是個(gè)包含了 Django 項(xiàng)目設(shè)置的 Python 模塊。
通常,這個(gè)配置文件使用 SQLite 作為默認(rèn)數(shù)據(jù)庫。如果你不熟悉數(shù)據(jù)庫,或者只是想嘗試下 Django,這是最簡單的選擇。Python 內(nèi)置 SQLite,所以你無需安裝額外東西來使用它。當(dāng)你開始一個(gè)真正的項(xiàng)目時(shí),你可能更傾向使用一個(gè)更具擴(kuò)展性的數(shù)據(jù)庫,例如 PostgreSQL,避免中途切換數(shù)據(jù)庫這個(gè)令人頭疼的問題。
如果你想使用其他數(shù)據(jù)庫,你需要安裝合適的 ?database bindings
? ,然后改變?cè)O(shè)置文件中 ?DATABASES 'default'
? 項(xiàng)目中的一些鍵值:
ENGINE
?-- 可選值有 ?'django.db.backends.sqlite3'
?,?'django.db.backends.postgresql'
?,?'django.db.backends.mysql'
?,或 ?'django.db.backends.oracle'
?。NAME
?-- 數(shù)據(jù)庫的名稱。如果你使用 SQLite,數(shù)據(jù)庫將是你電腦上的一個(gè)文件,在這種情況下,?NAME
應(yīng)該是此文件完整的絕對(duì)路徑,包括文件名。默認(rèn)值 ?BASE_DIR / 'db.sqlite3'
? 將把數(shù)據(jù)庫文件儲(chǔ)存在項(xiàng)目的根目錄。如果你不使用 SQLite,則必須添加一些額外設(shè)置,比如 ?USER
?、 ?PASSWORD
?、 ?HOST
?等等。
編輯 ?mysite/settings.py
? 文件前,先設(shè)置 ?TIME_ZONE
為你自己時(shí)區(qū)。
此外,關(guān)注一下文件頭部的 ?INSTALLED_APPS
設(shè)置項(xiàng)。這里包括了會(huì)在你項(xiàng)目中啟用的所有 Django 應(yīng)用。應(yīng)用能在多個(gè)項(xiàng)目中使用,你也可以打包并且發(fā)布應(yīng)用,讓別人使用它們。
通常, ?INSTALLED_APPS
默認(rèn)包括了以下 Django 的自帶應(yīng)用:
django.contrib.admin
? -- 管理員站點(diǎn), 你很快就會(huì)使用它。django.contrib.auth
? -- 認(rèn)證授權(quán)系統(tǒng)。django.contrib.contenttypes
? -- 內(nèi)容類型框架。django.contrib.sessions
? -- 會(huì)話框架。django.contrib.messages
? -- 消息框架。django.contrib.staticfiles
? -- 管理靜態(tài)文件的框架。這些應(yīng)用被默認(rèn)啟用是為了給常規(guī)項(xiàng)目提供方便。
默認(rèn)開啟的某些應(yīng)用需要至少一個(gè)數(shù)據(jù)表,所以,在使用他們之前需要在數(shù)據(jù)庫中創(chuàng)建一些表。請(qǐng)執(zhí)行以下命令:
...\> py manage.py migrate
這個(gè) ?migrate
命令查看 ?INSTALLED_APPS
?配置,并根據(jù) ?mysite/settings.py
? 文件中的數(shù)據(jù)庫配置和隨應(yīng)用提供的數(shù)據(jù)庫遷移文件(我們將在后面介紹這些),創(chuàng)建任何必要的數(shù)據(jù)庫表。你會(huì)看到它應(yīng)用的每一個(gè)遷移都有一個(gè)消息。如果你有興趣,運(yùn)行你的數(shù)據(jù)庫的命令行客戶端,輸入? \dt
? (PostgreSQL), ?SHOW TABLES;
?
(MariaDB,MySQL),? .tables
? (SQLite)或 ?SELECT TABLE_NAME FROM USER_TABLES;
? (Oracle)來顯示 Django 創(chuàng)建的表。
在 Django 里寫一個(gè)數(shù)據(jù)庫驅(qū)動(dòng)的 Web 應(yīng)用的第一步是定義模型 - 也就是數(shù)據(jù)庫結(jié)構(gòu)設(shè)計(jì)和附加的其它元數(shù)據(jù)。
在這個(gè)投票應(yīng)用中,需要?jiǎng)?chuàng)建兩個(gè)模型:問題 ?Question
?和選項(xiàng) ?Choice
?。?Question
?模型包括問題描述和發(fā)布時(shí)間。?Choice
?模型有兩個(gè)字段,選項(xiàng)描述和當(dāng)前得票數(shù)。每個(gè)選項(xiàng)屬于一個(gè)問題。
這些概念可以通過一個(gè) Python 類來描述。按照下面的例子來編輯 ?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)
每個(gè)模型被表示為 ?django.db.models.Model
? 類的子類。每個(gè)模型有許多類變量,它們都表示模型里的一個(gè)數(shù)據(jù)庫字段。
每個(gè)字段都是 ?Field
類的實(shí)例 - 比如,字符字段被表示為 ?CharField
,日期時(shí)間字段被表示為 ?DateTimeField
。這將告訴 Django 每個(gè)字段要處理的數(shù)據(jù)類型。
每個(gè) Field 類實(shí)例變量的名字(例如 ?question_text
?或 ?pub_date
?)也是字段名,所以最好使用對(duì)機(jī)器友好的格式。你將會(huì)在 Python 代碼里使用它們,而數(shù)據(jù)庫會(huì)將它們作為列名。
你可以使用可選的選項(xiàng)來為 Field 定義一個(gè)人類可讀的名字。這個(gè)功能在很多 Django 內(nèi)部組成部分中都被使用了,而且作為文檔的一部分。如果某個(gè)字段沒有提供此名稱,Django 將會(huì)使用對(duì)機(jī)器友好的名稱,也就是變量名。在上面的例子中,我們只為 ?Question.pub_date
? 定義了對(duì)人類友好的名字。對(duì)于模型內(nèi)的其它字段,它們的機(jī)器友好名也會(huì)被作為人類友好名使用。
定義某些 ?Field
?類實(shí)例需要參數(shù)。例如 ?CharField
?需要一個(gè) ?max_length
?參數(shù)。這個(gè)參數(shù)的用處不止于用來定義數(shù)據(jù)庫結(jié)構(gòu),也用于驗(yàn)證數(shù)據(jù),我們稍后將會(huì)看到這方面的內(nèi)容。
?Field
?也能夠接收多個(gè)可選參數(shù);在上面的例子中:我們將 ?votes
?的 ?default
?也就是默認(rèn)值,設(shè)為0。
注意在最后,我們使用 ?ForeignKey
?定義了一個(gè)關(guān)系。這將告訴 Django,每個(gè) ?Choice
?對(duì)象都關(guān)聯(lián)到一個(gè) ?Question
?對(duì)象。Django 支持所有常用的數(shù)據(jù)庫關(guān)系:多對(duì)一、多對(duì)多和一對(duì)一。
上面的一小段用于創(chuàng)建模型的代碼給了 Django 很多信息,通過這些信息,Django 可以:
schema
?(生成 ?CREATE TABLE
? 語句)。Question
?和 ?Choice
?對(duì)象進(jìn)行交互的 Python 數(shù)據(jù)庫 API。但是首先得把 ?polls
?應(yīng)用安裝到我們的項(xiàng)目里。
為了在我們的工程中包含這個(gè)應(yīng)用,我們需要在配置類 ?INSTALLED_APPS
?中添加設(shè)置。因?yàn)??PollsConfig
?類寫在文件 ?polls/apps.py
? 中,所以它的點(diǎn)式路徑是 ?'polls.apps.PollsConfig'
?。在文件 ?mysite/settings.py
? 中 ?INSTALLED_APPS
?子項(xiàng)添加點(diǎn)式路徑后,它看起來像這樣:
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
現(xiàn)在你的 Django 項(xiàng)目會(huì)包含 polls 應(yīng)用。接著運(yùn)行下面的命令:
...\> py manage.py makemigrations polls
你將會(huì)看到類似于下面這樣的輸出:
Migrations for 'polls':
polls/migrations/0001_initial.py
- Create model Question
- Create model Choice
通過運(yùn)行 ?makemigrations
?命令,Django 會(huì)檢測你對(duì)模型文件的修改(在這種情況下,你已經(jīng)取得了新的),并且把修改的部分儲(chǔ)存為一次 遷移。
遷移是 Django 對(duì)于模型定義(也就是你的數(shù)據(jù)庫結(jié)構(gòu))的變化的儲(chǔ)存形式 - 它們其實(shí)也只是一些你磁盤上的文件。如果你想的話,你可以閱讀一下你模型的遷移數(shù)據(jù),它被儲(chǔ)存在 ?polls/migrations/0001_initial.py
? 里。別擔(dān)心,你不需要每次都閱讀遷移文件,但是它們被設(shè)計(jì)成人類可讀的形式,這是為了便于你手動(dòng)調(diào)整 Django 的修改方式。
Django 有一個(gè)自動(dòng)執(zhí)行數(shù)據(jù)庫遷移并同步管理你的數(shù)據(jù)庫結(jié)構(gòu)的命令 - 這個(gè)命令是 ?migrate
?,我們馬上就會(huì)接觸它 - 但是首先,讓我們看看遷移命令會(huì)執(zhí)行哪些 SQL 語句。?sqlmigrate
?命令接收一個(gè)遷移的名稱,然后返回對(duì)應(yīng)的 SQL:
...\> py manage.py sqlmigrate polls 0001
你將會(huì)看到類似下面這樣的輸出(我把輸出重組成了人類可讀的格式):
BEGIN;
--
-- 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
);
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
"id" serial NOT NULL PRIMARY KEY,
"choice_text" varchar(200) NOT NULL,
"votes" integer NOT NULL,
"question_id" integer NOT NULL
);
ALTER TABLE "polls_choice"
ADD CONSTRAINT "polls_choice_question_id_c5b4b260_fk_polls_question_id"
FOREIGN KEY ("question_id")
REFERENCES "polls_question" ("id")
DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");
COMMIT;
請(qǐng)注意以下幾點(diǎn):
polls
?)和模型名的小寫形式( ?question
?和 ?choice
?)連接而來。(如果需要,你可以自定義此行為。)主鍵(IDs)會(huì)被自動(dòng)創(chuàng)建。(當(dāng)然,你也可以自定義。)"_id"
? 。(同樣,這也可以自定義。)FOREIGN KEY
? 生成。你不用關(guān)心 ?DEFERRABLE
部分,它只是告訴 PostgreSQL,請(qǐng)?jiān)谑聞?wù)全都執(zhí)行完之后再創(chuàng)建外鍵關(guān)系。auto_increment
(MySQL)、 ?serial
?(PostgreSQL)和 ?integer primary key ?autoincrement
? ?(SQLite),Django 會(huì)幫你自動(dòng)處理。那些和引號(hào)相關(guān)的事情 - 例如,是使用單引號(hào)還是雙引號(hào) - 也一樣會(huì)被自動(dòng)處理。sqlmigrate
命令并沒有真正在你的數(shù)據(jù)庫中的執(zhí)行遷移 - 相反,它只是把命令輸出到屏幕上,讓你看看 Django 認(rèn)為需要執(zhí)行哪些 SQL 語句。這在你想看看 Django 到底準(zhǔn)備做什么,或者當(dāng)你是數(shù)據(jù)庫管理員,需要寫腳本來批量處理數(shù)據(jù)庫時(shí)會(huì)很有用。如果你感興趣,你也可以試試運(yùn)行 ?python manage.py check ;
?這個(gè)命令幫助你檢查項(xiàng)目中的問題,并且在檢查過程中不會(huì)對(duì)數(shù)據(jù)庫進(jìn)行任何操作。
現(xiàn)在,再次運(yùn)行 ?migrate
命令,在數(shù)據(jù)庫里創(chuàng)建新定義的模型的數(shù)據(jù)表:
...\> py manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
Rendering model states... DONE
Applying polls.0001_initial... OK
這個(gè) ?migrate
命令選中所有還沒有執(zhí)行過的遷移(Django 通過在數(shù)據(jù)庫中創(chuàng)建一個(gè)特殊的表 ?django_migrations
來跟蹤執(zhí)行過哪些遷移)并應(yīng)用在數(shù)據(jù)庫上 - 也就是將你對(duì)模型的更改同步到數(shù)據(jù)庫結(jié)構(gòu)上。
遷移是非常強(qiáng)大的功能,它能讓你在開發(fā)過程中持續(xù)的改變數(shù)據(jù)庫結(jié)構(gòu)而不需要重新刪除和創(chuàng)建表 - 它專注于使數(shù)據(jù)庫平滑升級(jí)而不會(huì)丟失數(shù)據(jù)。我們會(huì)在后面的教程中更加深入的學(xué)習(xí)這部分內(nèi)容,現(xiàn)在,你只需要記住,改變模型需要這三步:
models.py
? 文件,改變模型。python manage.py makemigrations
? 為模型的改變生成遷移文件。python manage.py migrate
? 來應(yīng)用數(shù)據(jù)庫遷移。數(shù)據(jù)庫遷移被分解成生成和應(yīng)用兩個(gè)命令是為了讓你能夠在代碼控制系統(tǒng)上提交遷移數(shù)據(jù)并使其能在多個(gè)應(yīng)用里使用;這不僅僅會(huì)讓開發(fā)更加簡單,也給別的開發(fā)者和生產(chǎn)環(huán)境中的使用帶來方便。
現(xiàn)在讓我們進(jìn)入交互式 Python 命令行,嘗試一下 Django 為你創(chuàng)建的各種 API。通過以下命令打開 Python 命令行:
...\> py manage.py shell
我們使用這個(gè)命令而不是簡單的使用“python”是因?yàn)??manage.py
? 會(huì)設(shè)置 ?DJANGO_SETTINGS_MODULE
環(huán)境變量,這個(gè)變量會(huì)讓 Django 根據(jù) ?mysite/settings.py
? 文件來設(shè)置 Python 包的導(dǎo)入路徑。
當(dāng)你成功進(jìn)入命令行后,來試試 數(shù)據(jù)庫 API 吧:
>>> from polls.models import Choice, Question # Import the model classes we just wrote.
# No questions are in the system yet.
>>> Question.objects.all()
<QuerySet []>
# Create a new Question.
# Support for time zones is enabled in the default settings file, so
# Django expects a datetime with tzinfo for pub_date. Use timezone.now()
# instead of datetime.datetime.now() and it will do the right thing.
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())
# Save the object into the database. You have to call save() explicitly.
>>> q.save()
# Now it has an ID.
>>> q.id
1
# Access model field values via Python attributes.
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)
# Change values by changing the attributes, then calling save().
>>> q.question_text = "What's up?"
>>> q.save()
# objects.all() displays all the questions in the database.
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>
?<Question: Question object (1)>
? 對(duì)于我們了解這個(gè)對(duì)象的細(xì)節(jié)沒什么幫助。讓我們通過編輯 ?Question
?模型的代碼(位于 ?polls/models.py
? 中)來修復(fù)這個(gè)問題。給 ?Question
和 ?Choice
增加 ?__str__()
? 方法。
from django.db import models
class Question(models.Model):
# ...
def __str__(self):
return self.question_text
class Choice(models.Model):
# ...
def __str__(self):
return self.choice_text
給模型增加 ?__str__()
? 方法是很重要的,這不僅僅能給你在命令行里使用帶來方便,Django 自動(dòng)生成的 admin 里也使用這個(gè)方法來表示對(duì)象。
讓我們?cè)贋榇四P吞砑右粋€(gè)自定義方法:
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)
新加入的 ?import datetime
? 和 ?from django.utils import timezone
? 分別導(dǎo)入了 Python 的標(biāo)準(zhǔn) ?datetime
模塊和 Django 中和時(shí)區(qū)相關(guān)的 ?django.utils.timezone
? 工具模塊。
保存文件然后通過 ?python manage.py shell
命令再次打開 Python 交互式命令行:
>>> from polls.models import Choice, Question
# Make sure our __str__() addition worked.
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>
# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]>
# Get the question that was published this year.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>
# Request an ID that doesn't exist, this will raise an exception.
>>> Question.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Question matching query does not exist.
# Lookup by a primary key is the most common case, so Django provides a
# shortcut for primary-key exact lookups.
# The following is identical to Question.objects.get(id=1).
>>> Question.objects.get(pk=1)
<Question: What's up?>
# Make sure our custom method worked.
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True
# Give the Question a couple of Choices. The create call constructs a new
# Choice object, does the INSERT statement, adds the choice to the set
# of available choices and returns the new Choice object. Django creates
# a set to hold the "other side" of a ForeignKey relation
# (e.g. a question's choice) which can be accessed via the API.
>>> q = Question.objects.get(pk=1)
# Display any choices from the related object set -- none so far.
>>> q.choice_set.all()
<QuerySet []>
# Create three 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 objects have API access to their related Question objects.
>>> c.question
<Question: What's up?>
# And vice versa: Question objects get access to Choice objects.
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3
# The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships.
# This works as many levels deep as you want; there's no limit.
# Find all Choices for any question whose pub_date is in this year
# (reusing the 'current_year' variable we created above).
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
# Let's delete one of the choices. Use delete() for that.
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()
為你的員工或客戶生成一個(gè)用戶添加,修改和刪除內(nèi)容的后臺(tái)是一項(xiàng)缺乏創(chuàng)造性和乏味的工作。因此,Django 全自動(dòng)地根據(jù)模型創(chuàng)建后臺(tái)界面。
Django 產(chǎn)生于一個(gè)公眾頁面和內(nèi)容發(fā)布者頁面完全分離的新聞?lì)愓军c(diǎn)的開發(fā)過程中。站點(diǎn)管理人員使用管理系統(tǒng)來添加新聞、事件和體育時(shí)訊等,這些添加的內(nèi)容被顯示在公眾頁面上。Django 通過為站點(diǎn)管理人員創(chuàng)建統(tǒng)一的內(nèi)容編輯界面解決了這個(gè)問題。
管理界面不是為了網(wǎng)站的訪問者,而是為管理者準(zhǔn)備的。
首先,我們得創(chuàng)建一個(gè)能登錄管理頁面的用戶。請(qǐng)運(yùn)行下面的命令:
...\> py manage.py createsuperuser
鍵入你想要使用的用戶名,然后按下回車鍵:
Username: admin
然后提示你輸入想要使用的郵件地址:
Email address: admin@example.com
最后一步是輸入密碼。你會(huì)被要求輸入兩次密碼,第二次的目的是為了確認(rèn)第一次輸入的確實(shí)是你想要的密碼。
Password: **********
Password (again): *********
Superuser created successfully.
Django 的管理界面默認(rèn)就是啟用的。讓我們啟動(dòng)開發(fā)服務(wù)器,看看它到底是什么樣的。
如果開發(fā)服務(wù)器未啟動(dòng),用以下命令啟動(dòng)它:
...\> py manage.py runserver
現(xiàn)在,打開瀏覽器,轉(zhuǎn)到你本地域名的 “/admin/” 目錄, -- 比如 http://127.0.0.1:8000/admin/ 。你應(yīng)該會(huì)看見管理員登錄界面:
因?yàn)榉g功能默認(rèn)是開啟的,如果你設(shè)置了 ?LANGUAGE_CODE
?,登錄界面將顯示你設(shè)置的語言(如果 Django 有相應(yīng)的翻譯)。
現(xiàn)在,試著使用你在上一步中創(chuàng)建的超級(jí)用戶來登錄。然后你將會(huì)看到 Django 管理頁面的索引頁:
你將會(huì)看到幾種可編輯的內(nèi)容:組和用戶。它們是由 ?django.contrib.auth
? 提供的,這是 Django 開發(fā)的認(rèn)證框架。
但是我們的投票應(yīng)用在哪呢?它沒在索引頁面里顯示。
只需要再做一件事:我們得告訴管理,問題 ?Question
?對(duì)象需要一個(gè)后臺(tái)接口。打開 ?polls/admin.py
? 文件,把它編輯成下面這樣:
from django.contrib import admin
from .models import Question
admin.site.register(Question)
現(xiàn)在我們向管理頁面注冊(cè)了問題 ?Question
類。Django 知道它應(yīng)該被顯示在索引頁里:
點(diǎn)擊 "Questions" ?,F(xiàn)在看到是問題 "Questions" 對(duì)象的列表 "change list" 。這個(gè)界面會(huì)顯示所有數(shù)據(jù)庫里的問題 Question 對(duì)象,你可以選擇一個(gè)來修改。這里現(xiàn)在有我們?cè)谏弦徊糠种袆?chuàng)建的 “What's up?” 問題。
點(diǎn)擊 “What's up?” 來編輯這個(gè)問題(Question)對(duì)象:
注意事項(xiàng):
Question
?模型中自動(dòng)生成的DateTimeField
?、字符字段 ?CharField
?)會(huì)生成對(duì)應(yīng)的 HTML 輸入控件。每個(gè)類型的字段都知道它們?cè)撊绾卧诠芾眄撁胬镲@示自己。DateTimeField
?都有 JavaScript 寫的快捷按鈕。日期有轉(zhuǎn)到今天(Today)的快捷按鈕和一個(gè)彈出式日歷界面。時(shí)間有設(shè)為現(xiàn)在(Now)的快捷按鈕和一個(gè)列出常用時(shí)間的方便的彈出式列表。頁面的底部提供了幾個(gè)選項(xiàng):
Save
?) - 保存改變,然后返回對(duì)象列表。Save and continue editing
?) - 保存改變,然后重新載入當(dāng)前對(duì)象的修改界面。Save and add another
?) - 保存改變,然后添加一個(gè)新的空對(duì)象并載入修改界面。Delete
?) - 顯示一個(gè)確認(rèn)刪除頁面。如果顯示的 “發(fā)布日期(Date Published)” 和你在 教程 1 里創(chuàng)建它們的時(shí)間不一致,這意味著你可能沒有正確的設(shè)置 ?TIME_ZONE
。改變?cè)O(shè)置,然后重新載入頁面看看是否顯示了正確的值。
通過點(diǎn)擊 “今天(Today)” 和 “現(xiàn)在(Now)” 按鈕改變 “發(fā)布日期(Date Published)”。然后點(diǎn)擊 “保存并繼續(xù)編輯(Save and add another)”按鈕。然后點(diǎn)擊右上角的 “歷史(History)”按鈕。你會(huì)看到一個(gè)列出了所有通過 Django 管理頁面對(duì)當(dāng)前對(duì)象進(jìn)行的改變的頁面,其中列出了時(shí)間戳和進(jìn)行修改操作的用戶名:
更多建議: