先把github鏈接放上來:
https://github.com/q100036q/python_demo_learning_logs
第一:安裝Django
在windows系統(tǒng)下安裝和使用Django很簡單语御,而且為了創(chuàng)建新的工程項目,可以創(chuàng)建一個虛擬的環(huán)境來獨立的編程席怪。
創(chuàng)建新的虛擬項目和安裝Django的流程如下:
1.新建一個工程路徑应闯,打開控制臺,切換到這個路徑下挂捻。
2.輸入下面代碼創(chuàng)建一個虛擬環(huán)境:
python -m venv ll_env
3.激活虛擬環(huán)境碉纺,有兩種方法:第一是直接輸入:
ll_env\Scripts\activate
上述代碼進行創(chuàng)建,第二種是刻撒,打開ll_env\Scripts文件夾骨田,按住shift點擊鼠標右鍵,打開命令窗口再把activate.bat拖進去声怔。這種方法適合第一次之后的打開态贤,就不用再命令行手動操作了。
4.創(chuàng)建并激活虛擬環(huán)境后醋火,就可安裝Django了悠汽,輸入下面代碼:
pip install Django
第二:在Django中創(chuàng)建項目
1.創(chuàng)建項目路徑,用下面創(chuàng)建一個名為learning_log 的文件夾:
django-admin.py startproject learning_log .
可是經過測驗芥驳,上面教程中的代碼無效柿冲,在網上只能找到另一種方案,輸入下面代碼:
django-admin startproject learning_log .
最后的點不能省略兆旬,這個命令末尾的句點讓新項目使用合適的目錄結構假抄,manage.py這個文件會和ll_env文件夾同級,否則將會放進learning_log 文件夾下。
現(xiàn)在在ll_env文件夾同級目錄下慨亲,新出現(xiàn)了learning_log文件夾和manage.py文件。
2.創(chuàng)建數(shù)據(jù)庫宝鼓。使用manage.py文件進行數(shù)據(jù)庫的遷移指令刑棵,可以新建一個文件數(shù)據(jù)庫:
python manage.py migrate
這時候在ll_env文件夾同級目錄下又出現(xiàn)了一個名為db.sqlite3的數(shù)據(jù)庫文件。
3.查看項目是否能執(zhí)行愚铡。
python manage.py runserver
上述代碼能夠運行一個服務器蛉签,并顯示出來url路徑,這時候我們可以通過瀏覽器輸入它來訪問這個本地服務器沥寥。
第三:創(chuàng)建一個應用程序
1.在第二步運行了一個服務器的情況下碍舍,重新再manage.py的路徑下打開一個命令行窗口,并執(zhí)行激活(第一步的第3條)邑雅。
2.執(zhí)行命令startapp片橡,它可以創(chuàng)建一個在同級路徑下的應用程序。
python manage.py startapp learning_logs
可以看到淮野,文件夾路徑下多了一個名為learning_logs的文件夾捧书,這個和之前第二步第1條創(chuàng)建的learning_log有很大的區(qū)別,具體看下圖:
可以看到兩個文件夾內容完全不同骤星【桑可以這么理解,learning_log是我們控制中心洞难,存放一些配置相關的內容舆吮,而learning_logs是我們自己編寫程序的部分,用來管理數(shù)據(jù)队贱。
3.定義模型色冀,其實也就是創(chuàng)建各種各樣的類,來達到目的柱嫌,目前這個工程主要是用來保存數(shù)據(jù)呐伞,這里再models.py文件下定義兩個類,一個用于保存標題慎式,另一個保存內容伶氢,后者需要鏈接到前者。先看代碼:
#models.py
from django.db import models
class Topic(models.Model):
text = models.CharField(max_length = 200);
date_added = models.DateTimeField(auto_now_add = True);
def __str__(self):
return self.text;
class Entry(models.Model):
topic = models.ForeignKey(Topic,on_delete = models.CASCADE);
text = models.TextField();
date_added = models.DateTimeField(auto_now_add=True);
class Meta:
verbose_name_plural = 'entries';
def __str__(self):
if len(self.text) > 50:
return self.text[:50] + '...';
else:
return self.text;
models.CharField是儲存字符或文本數(shù)據(jù)瘪吏,models.TextField類似癣防,但是是沒有長度限制,顯示在web上出來是一個文本框掌眠。
1)這里重點一個是on_delete = models.CASCADE這段代碼蕾盯,如果不加會報錯,主要是因為Django更新至2.0以上版本了蓝丙。
2)方法str() 告訴Django级遭,呈現(xiàn)條目時應顯示哪些信息望拖。
3)我們在Entry 類中嵌套了Meta 類。Meta 存儲用于管理模型的額外信息挫鸽,在這里说敏,它讓我們能夠設置一個特殊屬性,讓Django在需要時使用Entries 來表示多個條目丢郊。如果沒有這個類盔沫, Django將使用Entrys來表示多個條目。(這段還沒搞懂)枫匾。
4)Entry的第一個屬性topic 是一個ForeignKey 實例架诞。外鍵是一個數(shù)據(jù)庫術語,它引用了數(shù)據(jù)庫中的另一條記錄干茉;這些代碼將每個條目關聯(lián)到特定的主題谴忧。每個主題創(chuàng)建時,都給它分配了一個鍵(或ID)角虫。需要在兩項數(shù)據(jù)之間建立聯(lián)系時俏蛮,Django使用與每項信息相關聯(lián)的鍵。
4.激活模型上遥,要使用模型搏屑,必須讓Django將應用程序包含到項目中。這里需要用learning_log中的settings.py文件粉楚,并在INSTALLED_APPS里包含learning_logs內容:
#settings.py
INSTALLED_APPS = (
--snip--
'django.contrib.staticfiles',
# 我的應用程序
'learning_logs',
)
5.接下來辣恋,修改數(shù)據(jù)庫,使其能保存我們在models.py中定義的模型:
python manage.py makemigrations learning_logs
接著進行數(shù)據(jù)庫的遷移模软,為我們的新模型去創(chuàng)建一個表:
python manage.py migrate
6.Django管理網站伟骨,首先添加一個超級管理員的權限,這樣能在web上修改添加內容:
python manage.py createsuperuser
按照提示輸入自己的信息即可燃异。
接著携狭,向管理網站注冊模型,之前定義的兩個模型回俐,在這里要進行注冊逛腿,注冊的代碼寫在admin.py中:
#admin.py
from django.contrib import admin;
from learning_logs.models import Topic,Entry;
admin.site.register(Topic);
admin.site.register(Entry);
最后就可以訪問http://localhost:8000/admin/ ,輸入賬號密碼進入后臺仅颇,此時可以針對Topic和Entry進行編輯了单默,由于綁定外鍵的關系,一定要有一個Topic內容忘瓦,才能去添加Entry搁廓。
7.Django shell,可以使用shell來探索存儲在項目數(shù)據(jù)庫中的數(shù)據(jù)。
python manage.py shell
上面代碼可以運行到shell中境蜕,運行下面腳本蝙场,查看下我們數(shù)據(jù)庫的內容:
from learning_logs.models import Topic
topics = Topic.objects.all()
for topic in topics:
print(topic.id, topic)
t = Topic.objects.get(id=1)
t.text
t.entry_set.all()
最后這條t.entry_set.all(),為通過外鍵關系獲取數(shù)據(jù)粱年,可使用相關模型的小寫名稱售滤、下劃線和單詞set。
8.遇到的問題:
1)每次修改模型(manage.py文件)逼泣,要重啟shell;
2)有的時候如果增加了新模型舟舒,要去修改admin.py增加新的注冊拉庶。
3)一般情況下,不需要重啟服務器秃励,但是如果一直不響應的情況下氏仗,可以ctrl+c關閉,在使用第二步的第3條重啟夺鲜。
4)關閉shall的方法:ctrl+z再回車即可皆尔。
第四:映射URL
簡單的說就是設置打開瀏覽器的頁面。這里先修改默認的主頁币励。
1.修改主目錄url內容慷蠕,打開項目主文件夾learning_log中的文件urls.py,這里添加內容:
#urls.py(learning_log/urls.py)
from django.contrib import admin;
from django.urls import path,include;
from django.conf.urls import url;
urlpatterns = [
path('admin/', admin.site.urls),
# path(r'',include('learning_logs.urls',namespace = 'learning_logs')),
url(r'',include('learning_logs.urls',namespace = 'learning_logs'))
]
在Django1.11中路由函數(shù)為url()食呻,在Django2中路由函數(shù)改成了path()流炕,不過路由函數(shù)向下兼容,在Django2中同樣可以使用url()函數(shù)仅胞,這里列出兩種寫法每辟,注意引入對應的模塊,這里加載指向learning_logs.urls這個文件干旧,namespace只是為了和別的url作區(qū)分渠欺。
2.添加新目錄下的url,填寫現(xiàn)在我們需要在文件夾learning_logs中創(chuàng)建另一個urls.py文件椎眯,內容如下:
#urls.py
from django.conf.urls import url;
from . import views;
app_name='learning_logs'
urlpatterns = [
url(r'^$',views.index,name = 'index'),
]
我們來看看正則表達式r'^$' 挠将。其中的r 讓Python將接下來的字符串視為原始字符串,而引號告訴Python正則表達式始于和終于何處编整。脫字符(^ )讓Python查看字符串的開頭捐名,而美元符號讓Python查看字符串的末尾∧只鳎總體而言镶蹋,這個正則表達式讓Python查找開頭和末尾之間沒有任何東西的URL。Python忽略項目的基礎URL(http://localhost:8000/),因此這個正則表達式與基礎URL匹配贺归。
url() 的第二個實參指定了要調用的視圖函數(shù)淆两。請求的URL與前述正則表達式匹配時,Django將調用views.index (這個視圖函數(shù)將在下一節(jié)編寫)拂酣。第三個實參將這個URL模式的名稱指定為index秋冰,讓我們能夠在代碼的其他地方引用它。每當需要提供到這個主頁的鏈接時婶熬,我們都將使用這個名稱剑勾,而不編寫URL。
3.編寫視圖內容赵颅,視圖函數(shù)接受請求中的信息虽另,準備好生成網頁所需的數(shù)據(jù),再將這些數(shù)據(jù)發(fā)送給瀏覽器饺谬,這個依據(jù)模板代碼來實現(xiàn)不同的效果捂刺,這里我們修改views.py文件:
#views.py
from django.shortcuts import render
def index(request):
"""學習筆記的主頁"""
return render(request, 'learning_logs/index.html')
URL請求與我們剛才定義的模式匹配時,Django將在文件views.py中查找函數(shù)index() 募寨,再將請求對象傳遞給這個視圖函數(shù)族展。
4.編寫網頁模板。在文件夾learning_logs中新建一個文件夾拔鹰,并將其命名為templates仪缸。在文件夾templates中,再新建一個文件夾列肢,并將其命名為learning_logs腹殿。在最里面的文件夾learning_logs中,新建一個文件例书,并將其命名為index.html锣尉,再在這個文件中編寫如下代碼:
#index.html
<p>Learning Log</p>
<p>Learning Log helps you keep track of your learning, for any topic you'relearning about.</p>
這樣就完成了主頁的編輯。
5.幾個要點:
1)urls.py文件中的urlpatterns不能寫錯决采,否則會報錯自沧。
2)新創(chuàng)建的子文件夾的urls.py文件需要添加下面這行代碼,否則會報錯:
app_name='learning_logs'
這是因為之前定義了namespace屬性树瞭, [app_name]代表你的應用的名稱拇厢。
3)這篇代碼編寫完成后不用重啟服務器,在setting.py中設置了DEBUG = True晒喷,瀏覽器會自動刷新我們剛保存的代碼孝偎。但是,實際運用中DEBUG不能設置為true凉敲。
第五:創(chuàng)建其它網頁:
這段是對網頁和之前的數(shù)據(jù)綁定衣盾,把之前存入數(shù)據(jù)庫的內容展示出來寺旺。
1.模板繼承,可以創(chuàng)建一個父模板势决,讓其他模板(網頁代碼)都繼承它阻塑,可以方便統(tǒng)一修改。
下面果复,為了給幾個子網頁都添加一個統(tǒng)一的內容陈莽,父模板僅僅制作帶鏈接的標題,可以讓子模板點擊回到主頁虽抄。base.html內容如下:
#base.html
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a>
<!--><a href="{% url 'learning_logs:topics' %}">Topics</a><-->
</p>
{% block content %}{% endblock content %}
有網頁制作相關知識的就知道<p>是一個段落標簽走搁,<a>是一個超鏈接標簽,href指向一個鏈接迈窟,這里{%%}是一個模板標簽私植,內容就指向了learning_logs下的index文件,即主頁菠隆。{% block content %}{% endblock content %}是一對占位符兵琳,具體內容由子模板指定狂秘。中間這段被注釋的代碼在后面顯示次級界面的時候要解開注釋『Ь叮現(xiàn)在重新編輯index.html文件,讓他繼承父模板base.html:
#index.html
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Learning Log helps you keep track of your learning,for any topic you're learning about.</p>
{% endblock content %}
extends 表示繼承的路徑內容者春。占位符內容就是這個子模板獨有的內容破衔。它因為繼承自base.html,現(xiàn)在可以顯示如下:
2.顯示主題頁面钱烟,為了增加新的下一級別的網頁晰筛,這里要去修改urls.py文件,增加了一行內容:
#urls.py
from django.conf.urls import url;
from . import views;
app_name='learning_logs'
urlpatterns = [
url(r'^$',views.index,name = 'index'),
url(r'^topics/$',views.topics,name = 'topics'),
]
正則表達式中添加了topics/這一段拴袭,說明我們現(xiàn)在匹配的網址應該是:http://127.0.0.1:8000/topics/读第。其URL與該模式匹配的請求都將交給views.py中的函數(shù)topics() 進行處理。接下來拥刻,我們去這個文件中把它添加上:
#views.py
from django.shortcuts import render;
from .models import Topic;
def index(request):
return render(request,'learning_logs/index.html');
def topics(request):
topics = Topic.objects.order_by('date_added');
context = {'topics':topics}
return render(request,'learning_logs/topics.html',context)
這里是一個難點怜瞒,可能都已經忘記了之前我們做的操作了,這時候翻上去看第三步的第3段般哼,我們在models.py文件內寫下了Topic這個模型吴汪,并且定義了name和date_added這個屬性,order_by對其排序蒸眠,取出所有的值漾橙,然后保存為一個字典文件,并命名為context再通過render傳遞到topics.html里接收±憧ǎ現(xiàn)在當然是創(chuàng)建一個名為topics.html的頁面文件了:
#topics.html
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics</p>
<ul>
{% for topic in topics %}
<li>
<!-->注意霜运,這段在下面創(chuàng)建topic.html的時候放開注釋脾歇,為的是創(chuàng)建一個指向下一層級的超鏈接,并且將topic.id 傳遞到topic.html文件中
<a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a>
<-->
{{ topic }}
</li>
{% empty %}
<li>No topics have been added yet.</li>
{% endfor %}
</ul>
{% endblock content %}
依照下圖觉渴,可以看出上面代碼說的到底是啥介劫,<ul><li>分別代表無序列表和列表項的標簽, {% for%}和 {% endfor %}用來當做一個for循環(huán)案淋,讀取views.py傳遞過來的內容座韵,并做成超鏈接虱疏,{{ topic }} 是將每一項名稱都顯示藐唠,不是使用一對,而是兩對舌缤,不然顯示的內容是:{ topic }瓣距。{% empty %}這個告訴了我們黔帕,這個循環(huán)內容為空的時候顯示什么東西。
這時候蹈丸,上面第五步的第1段中的注釋代碼要解開成黄。
3.顯示對應主題的內容。
之前逻杖,我們在定義文件的標題的同時也保存了相應的內容奋岁,這里我們點擊每個列表項之后,打開新的頁面去顯示它荸百。為了打開新的頁面闻伶,必須去urls.py增加新的配置:
#urls.py
from django.conf.urls import url;
from . import views;
app_name='learning_logs'
urlpatterns = [
url(r'^$',views.index,name = 'index'),
url(r'^topics/$',views.topics,name = 'topics'),
url(r'^topics/(?P<topic_id>\d+)/$',views.topic,name = 'topic'),
]
最后一行新增內容:在r'^$'直接加入了topics/(?P<topic_id>\d+)/這么一句正則表達式,作用就是匹配到http://localhost:8000/topics/1/這樣的URL够话,d+表示任意數(shù)字蓝翰,(?P)為命名捕獲,是捕獲內容儲存到topic_id中女嘲,這個是python專有的語法畜份。接下來還是根據(jù)這里設置的views.topic去views.py文件中新增topic函數(shù):
#views.py
from django.shortcuts import render;
from .models import Topic;
def index(request):
return render(request,'learning_logs/index.html');
def topics(request):
topics = Topic.objects.order_by('date_added');
context = {'topics':topics}
return render(request,'learning_logs/topics.html',context)
def topic(request,topic_id):
topic = Topic.objects.get(id = topic_id);
entries = topic.entry_set.order_by('-date_added');
context = {'topic':topic,'entries':entries}
return render(request,'learning_logs/topic.html',context)
topic函數(shù)傳入剛剛捕獲到的參數(shù)topic_id,然后根據(jù)之前在shell里學習的方法欣尼,去數(shù)據(jù)庫中讀取數(shù)據(jù)爆雹,再通過date_added倒序排序,entry_set讀取出我們之前存入數(shù)據(jù)庫中的內容(忘記的話參考第三步的第7條)媒至,存進字典新增一項顶别。最后通過render一起傳給topic.html。
注意拒啰,這時候要把第五步第2段中topics.html文件中的注釋解開驯绎。
這時候創(chuàng)建這個文件:
#topic.html
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics:{{topic}}</p>
<p>Entries:</p>
<ul>
{% for entry in entries %}
<li>
<p>{{ entry.date_add|date:'M d,Y H:i'}}</p>
<p>{{ entry.text|linebreaks }}</p>
</li>
{% empty %}
<li>There are no entries for this topic yet.</li>
{% endfor %}
</ul>
{% endblock content %}
這里其實很好理解,首先顯示Topics的值谋旦,這個在views.py里獲得了剩失。然后通過for循環(huán)讀取entries里面的內容屈尼,并且對應的格式化顯示,|符合是一個過濾器拴孤,linebreaks 作用是將包含換行符的長條目轉換為瀏覽器能夠理解的格式脾歧。這一切完成之后,顯示內容如下圖:
第六:總結
總得縷了一下演熟,django框架可以把數(shù)據(jù)庫鞭执,網頁結合起來,就不用和javaSE那樣分開做了芒粹,目前這個案例最傻的就是命名太相似兄纺,這樣要深刻理解代碼中寫的到底是指什么,代碼互相調用化漆,文件互相調用要深刻理解估脆,下面是我整理的調用流程:
下面是發(fā)現(xiàn)的一個容易出錯的問題,在<a>標簽頁內座云,'url'這個和之后的內容一定要分開疙赠,如果和下圖一樣連著,就會出現(xiàn)下面報錯k稀F匝簟!