先把github鏈接放上來:
https://github.com/q100036q/python_demo_learning_logs
第一:安裝Django
在windows系統下安裝和使用Django很簡單,而且為了創建新的工程項目,可以創建一個虛擬的環境來獨立的編程。
創建新的虛擬項目和安裝Django的流程如下:
1.新建一個工程路徑,打開控制臺,切換到這個路徑下。
2.輸入下面代碼創建一個虛擬環境:
python -m venv ll_env
3.激活虛擬環境,有兩種方法:第一是直接輸入:
ll_env\Scripts\activate
上述代碼進行創建,第二種是,打開ll_env\Scripts文件夾,按住shift點擊鼠標右鍵,打開命令窗口再把activate.bat拖進去。這種方法適合第一次之后的打開,就不用再命令行手動操作了。
4.創建并激活虛擬環境后,就可安裝Django了,輸入下面代碼:
pip install Django
第二:在Django中創建項目
1.創建項目路徑,用下面創建一個名為learning_log 的文件夾:
django-admin.py startproject learning_log .
可是經過測驗,上面教程中的代碼無效,在網上只能找到另一種方案,輸入下面代碼:
django-admin startproject learning_log .
最后的點不能省略,這個命令末尾的句點讓新項目使用合適的目錄結構,manage.py這個文件會和ll_env文件夾同級,否則將會放進learning_log 文件夾下。
現在在ll_env文件夾同級目錄下,新出現了learning_log文件夾和manage.py文件。
2.創建數據庫。使用manage.py文件進行數據庫的遷移指令,可以新建一個文件數據庫:
python manage.py migrate
這時候在ll_env文件夾同級目錄下又出現了一個名為db.sqlite3的數據庫文件。
3.查看項目是否能執行。
python manage.py runserver
上述代碼能夠運行一個服務器,并顯示出來url路徑,這時候我們可以通過瀏覽器輸入它來訪問這個本地服務器。
第三:創建一個應用程序
1.在第二步運行了一個服務器的情況下,重新再manage.py的路徑下打開一個命令行窗口,并執行激活(第一步的第3條)。
2.執行命令startapp,它可以創建一個在同級路徑下的應用程序。
python manage.py startapp learning_logs
可以看到,文件夾路徑下多了一個名為learning_logs的文件夾,這個和之前第二步第1條創建的learning_log有很大的區別,具體看下圖:
可以看到兩個文件夾內容完全不同??梢赃@么理解,learning_log是我們控制中心,存放一些配置相關的內容,而learning_logs是我們自己編寫程序的部分,用來管理數據。
3.定義模型,其實也就是創建各種各樣的類,來達到目的,目前這個工程主要是用來保存數據,這里再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是儲存字符或文本數據,models.TextField類似,但是是沒有長度限制,顯示在web上出來是一個文本框。
1)這里重點一個是on_delete = models.CASCADE這段代碼,如果不加會報錯,主要是因為Django更新至2.0以上版本了。
2)方法str() 告訴Django,呈現條目時應顯示哪些信息。
3)我們在Entry 類中嵌套了Meta 類。Meta 存儲用于管理模型的額外信息,在這里,它讓我們能夠設置一個特殊屬性,讓Django在需要時使用Entries 來表示多個條目。如果沒有這個類, Django將使用Entrys來表示多個條目。(這段還沒搞懂)。
4)Entry的第一個屬性topic 是一個ForeignKey 實例。外鍵是一個數據庫術語,它引用了數據庫中的另一條記錄;這些代碼將每個條目關聯到特定的主題。每個主題創建時,都給它分配了一個鍵(或ID)。需要在兩項數據之間建立聯系時,Django使用與每項信息相關聯的鍵。
4.激活模型,要使用模型,必須讓Django將應用程序包含到項目中。這里需要用learning_log中的settings.py文件,并在INSTALLED_APPS里包含learning_logs內容:
#settings.py
INSTALLED_APPS = (
--snip--
'django.contrib.staticfiles',
# 我的應用程序
'learning_logs',
)
5.接下來,修改數據庫,使其能保存我們在models.py中定義的模型:
python manage.py makemigrations learning_logs
接著進行數據庫的遷移,為我們的新模型去創建一個表:
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來探索存儲在項目數據庫中的數據。
python manage.py shell
上面代碼可以運行到shell中,運行下面腳本,查看下我們數據庫的內容:
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(),為通過外鍵關系獲取數據,可使用相關模型的小寫名稱、下劃線和單詞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中路由函數為url(),在Django2中路由函數改成了path(),不過路由函數向下兼容,在Django2中同樣可以使用url()函數,這里列出兩種寫法,注意引入對應的模塊,這里加載指向learning_logs.urls這個文件,namespace只是為了和別的url作區分。
2.添加新目錄下的url,填寫現在我們需要在文件夾learning_logs中創建另一個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查看字符串的末尾??傮w而言,這個正則表達式讓Python查找開頭和末尾之間沒有任何東西的URL。Python忽略項目的基礎URL(http://localhost:8000/),因此這個正則表達式與基礎URL匹配。
url() 的第二個實參指定了要調用的視圖函數。請求的URL與前述正則表達式匹配時,Django將調用views.index (這個視圖函數將在下一節編寫)。第三個實參將這個URL模式的名稱指定為index,讓我們能夠在代碼的其他地方引用它。每當需要提供到這個主頁的鏈接時,我們都將使用這個名稱,而不編寫URL。
3.編寫視圖內容,視圖函數接受請求中的信息,準備好生成網頁所需的數據,再將這些數據發送給瀏覽器,這個依據模板代碼來實現不同的效果,這里我們修改views.py文件:
#views.py
from django.shortcuts import render
def index(request):
"""學習筆記的主頁"""
return render(request, 'learning_logs/index.html')
URL請求與我們剛才定義的模式匹配時,Django將在文件views.py中查找函數index() ,再將請求對象傳遞給這個視圖函數。
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)新創建的子文件夾的urls.py文件需要添加下面這行代碼,否則會報錯:
app_name='learning_logs'
這是因為之前定義了namespace屬性, [app_name]代表你的應用的名稱。
3)這篇代碼編寫完成后不用重啟服務器,在setting.py中設置了DEBUG = True,瀏覽器會自動刷新我們剛保存的代碼。但是,實際運用中DEBUG不能設置為true。
第五:創建其它網頁:
這段是對網頁和之前的數據綁定,把之前存入數據庫的內容展示出來。
1.模板繼承,可以創建一個父模板,讓其他模板(網頁代碼)都繼承它,可以方便統一修改。
下面,為了給幾個子網頁都添加一個統一的內容,父模板僅僅制作帶鏈接的標題,可以讓子模板點擊回到主頁。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 %}是一對占位符,具體內容由子模板指定。中間這段被注釋的代碼在后面顯示次級界面的時候要解開注釋?,F在重新編輯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,現在可以顯示如下:
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/這一段,說明我們現在匹配的網址應該是:http://127.0.0.1:8000/topics/。其URL與該模式匹配的請求都將交給views.py中的函數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里接收。現在當然是創建一個名為topics.html的頁面文件了:
#topics.html
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics</p>
<ul>
{% for topic in topics %}
<li>
<!-->注意,這段在下面創建topic.html的時候放開注釋,為的是創建一個指向下一層級的超鏈接,并且將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循環,讀取views.py傳遞過來的內容,并做成超鏈接,{{ topic }} 是將每一項名稱都顯示,不是使用一對,而是兩對,不然顯示的內容是:{ topic }。{% empty %}這個告訴了我們,這個循環內容為空的時候顯示什么東西。
這時候,上面第五步的第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+表示任意數字,(?P)為命名捕獲,是捕獲內容儲存到topic_id中,這個是python專有的語法。接下來還是根據這里設置的views.topic去views.py文件中新增topic函數:
#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函數傳入剛剛捕獲到的參數topic_id,然后根據之前在shell里學習的方法,去數據庫中讀取數據,再通過date_added倒序排序,entry_set讀取出我們之前存入數據庫中的內容(忘記的話參考第三步的第7條),存進字典新增一項。最后通過render一起傳給topic.html。
注意,這時候要把第五步第2段中topics.html文件中的注釋解開。
這時候創建這個文件:
#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循環讀取entries里面的內容,并且對應的格式化顯示,|符合是一個過濾器,linebreaks 作用是將包含換行符的長條目轉換為瀏覽器能夠理解的格式。這一切完成之后,顯示內容如下圖:
第六:總結
總得縷了一下,django框架可以把數據庫,網頁結合起來,就不用和javaSE那樣分開做了,目前這個案例最傻的就是命名太相似,這樣要深刻理解代碼中寫的到底是指什么,代碼互相調用,文件互相調用要深刻理解,下面是我整理的調用流程:
下面是發現的一個容易出錯的問題,在<a>標簽頁內,'url'這個和之后的內容一定要分開,如果和下圖一樣連著,就會出現下面報錯?。?!