Django入門(一)

跟書《python編程:從入門到實踐》,學習用Django編寫名爲「學習筆記」的Web應用程序。html

創建項目

項目路徑:learning_logpython

  • 安裝python3.7:

此處省略,參考這裏:http://www.javashuo.com/article/p-qplknasp-db.htmlweb

  • 創建虛擬環境:
# cd /opt/# mkdir learning_log && cd learning_log# python -m venv 11_env

  • 激活虛擬環境:
# source ll_env/bin/activate

進入虛擬環境終端。正則表達式

要中止使用虛擬環境,可執行:sql

# deactivate

  • 安裝Django:
# pip3 install Django

Django僅在虛擬環境處於活動狀態時纔可用。shell

下面與書中不一樣部分是因爲Django版本更新致使,照着操做便可。本人Django版本爲2.2.3,可經過命令python -m django --version查看Django版本。數據庫

  • 在Django中建立項目:
# django-admin.py startproject learning_log .# lslearning_log  ll_env  manage.py# ls learning_log/__init__.py  settings.py  urls.py  wsgi.py

Django新建了一個名爲learning_log的目錄。它還建立了一個名爲manage.py的文件,這是一個簡單的程序,它接受命令並將其交給Django的相關部分去運行。django

目錄learning_log包含4個文件,其中最重要的是settings.pyurls.pywsgi.py編程

文件settings.py指定Django如何與你的系統交互以及如何管理項目。
文件urls.py告訴Django應建立哪些網頁來響應瀏覽器請求。
文件wsgi.py幫助Django提供它建立的文件,這個文件名是web server gateway interface(Web服務器網關接口)的首字母縮寫。vim

  • 建立數據庫:
# python manage.py migrate

報錯:

django.core.exceptions.ImproperlyConfigured: SQLite 3.8.3 or later is required (found 3.7.17).

查看系統的sqlite3版本:

# sqlite3 --version3.7.17 2013-05-20 00:56:22 118a3b35693b134d56ebd780123b7fd6f1497668

系統自帶的sqlite3版本比較低,須要更新版本。

  • 更新sqlite3版本:
#下載安裝# cd /software# wget https://www.sqlite.org/2019/sqlite-autoconf-3270200.tar.gz# tar -zxf sqlite-autoconf-3270200.tar.gz# cd sqlite-autoconf-3270200# ./configure --prefix=/usr/local/# make && make install

#更換版本# find /usr -name sqlite3/usr/bin/sqlite3
/usr/lib64/python2.7/sqlite3
/usr/local/bin/sqlite3
/usr/python/lib/python3.7/sqlite3# /usr/local/bin/sqlite3 --version3.27.2 2019-02-25 16:06:06 bd49a8271d650fa89e446b42e513b595a717b9212c91dd384aab871fc1d0f6d7# mv /usr/bin/sqlite3 /usr/bin/sqlite3.bak# ln -s /usr/local/bin/sqlite3 /usr/bin/sqlite3# sqlite3 --version3.27.2 2019-02-25 16:06:06 bd49a8271d650fa89e446b42e513b595a717b9212c91dd384aab871fc1d0f6d7

#路徑傳遞給共享庫# echo 'export LD_LIBRARY_PATH="/usr/local/lib"' >> ~/.bashrc# source !$# cd /opt/learning_log/# rm -rf /software/sqlite-autoconf-3270200*

  • 繼續建立數據庫:
# python manage.py migrate# lsdb.sqlite3  learning_log  ll_env  manage.py

  • 查看項目:

對於虛擬機環境,建議指定本機IP和端口,不然默認是127.0.0.1:8000,瀏覽器會沒法訪問。

# python manage.py runserver 192.168.30.128:8000# vim learning_log/settings.pyALLOWED_HOSTS = ['192.168.30.128']              #容許主機中,添加本機IP或*(任意主機)

Django啓動一個服務器,讓你可以查看系統中的項目,瞭解它們的工做狀況。當你在瀏覽器中輸入URL以請求網頁時,該Django服務器將進行響應:生成合適的網頁,並將其發送給瀏覽器。

打開瀏覽器,輸入192.168.30.128:8000訪問Django項目,以下圖:

在這裏插入圖片描述


建立應用程序

應用路徑:learning_logs

Django項目由一系列應用程序組成,它們協同工做,讓項目成爲一個總體。咱們暫時只建立一個應用程序,它將完成項目的大部分工做。


激活虛擬環境

虛擬機再打開一個終端

# cd /opt/learning_log/# source ll_env/bin/activate

# python manage.py startapp learning_logs# lsdb.sqlite3  learning_log  learning_logs  ll_env  manage.py# ls learning_logs/admin.py  apps.py  __init__.py  migrations  models.py  tests.py  views.py

上面新增了learning_logs目錄,其中models.py用來定義咱們要在應用程序中管理的數據。


定義模型

# vim learning_logs/models.py

from django.db import modelsclass Topic(models.Model):
    """用戶學習的主題"""
    text = models.CharField(max_length=200)
    date_added = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        """返回模型的字符串表示"""
        return self.text

建立了一個名爲Topic的類,它繼承了Model——Django中一個定義了模型基本功能的類。Topic類只有兩個屬性:textdate_added

屬性text是一個CharField——由字符或文本組成的數據,須要存儲少許的文本,如名稱、標題或城市時,可以使用CharField。定義CharField屬性時,須要告訴Django該在數據庫中預留多少空間,這裏設置爲200個字符。

屬性date_added是一個DateTimeField——記錄日期和時間的數據。傳遞了實參auto_add_now=True,每當用戶建立新主題時,這都讓Django將這個屬性自動設置成當前日期和時間。


激活模型

要使用模型,必須讓Django將應用程序包含到項目中。

# vim learning_log/settings.pyINSTALLED_APPS = [
    'django.contrib.admin',    'django.contrib.auth',    'django.contrib.contenttypes',    'django.contrib.sessions',    'django.contrib.messages',    'django.contrib.staticfiles',    # 個人應用程序
    'learning_logs',                #增長該行]

還須要讓Django修改數據庫,使其可以存儲於模型Topic相關的信息。

# python manage.py makemigrations learning_logs# python manage.py migrate

在這裏,Django確認爲learning_logs 應用遷移時一切OK。

每當須要修改項目管理的數據時,都採起以下三個步驟:

  1. 修改models.py
  2. learning_logs調用makemigrations
  3. 讓Django遷移項目。

Django管理網站

  • 建立超級用戶:Django容許建立具有全部權限的用戶——超級用戶。
# python manage.py createsuperuserUsername (leave blank to use 'root'): ll_admin              #自定義用戶名Email address:              #可爲空Password:               #自定義密碼,不小於8位Password (again): 
Superuser created successfully.

  • 向管理網站註冊模型:非自動建立的模型須要手工註冊。
# vim learning_logs/admin.py

from django.contrib import adminfrom learning_logs.models import Topic

admin.site.register(Topic)

導入咱們要註冊的模型Topic,讓Django經過管理網站管理咱們的模型。使用超級用戶訪問管理網站:192.168.30.128:8000/admin/

在這裏插入圖片描述

在這裏插入圖片描述

  • 添加主題:註冊Topic後,添加主題Chess和Rock Climbing。

在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述


定義模型Entry

要記錄學到的Chess和Rock Climbing知識,須要爲用戶可在「學習筆記」中添加的條目定義模型。每一個條目都與特定主題相關聯,這種關係被稱爲多對一關係,即多個條目可關聯到同一個主題。

# vim learning_logs/models.py

from django.db import modelsclass Topic(models.Model):
    """用戶學習的主題"""
    text = models.CharField(max_length=200)
    date_added = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        """返回模型的字符串表示"""
        return self.textclass Entry(models.Model):
    """學到的有關某個主題的具體知識"""
    topic = models.ForeignKey(Topic)
    text = models.TextField()
    date_added = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        verbose_name_plural = 'entries'

    def __str__(self):
        """返回模型的字符串表示"""
        return self.text[:50] + "..."

像Topic同樣,Entry也繼承了Django基類Model。屬性topic是一個ForeignKey實例,外鍵引用了數據庫中的另外一條記錄,這些代碼將每一個條目關聯到特定的主題。每一個主題建立時,都給它分配了一個鍵(ID),在兩項數據之間須要創建聯繫時,Django使用與每項信息相關聯的鍵。

屬性text是一個TextField實例,這個字段不須要限制長度。屬性date_added可以按建立順序呈現條目,且在每一個條目旁邊放置時間戳。

在Entry類中嵌套Meta類,Meta類存儲用於管理模型的額外信息,使用一個特殊屬性讓Django在須要時使用Entries來表示多個條目;若是沒有這個類,Django將使用Entrys來表示多個條目。方法__str__()告訴Django在呈現條目時應顯示text的前50個字符,超出則用...顯示。


遷移模型Entry

# python manage.py makemigrations learning_logs

報錯:

TypeError: __init__() missing 1 required positional argument: 'on_delete'

解決——修改models.py

from django.db import modelsclass Topic(models.Model):
    """用戶學習的主題"""
    text = models.CharField(max_length=200)
    date_added = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        """返回模型的字符串表示"""
        return self.textclass 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):
        """返回模型的字符串表示"""
        return self.text[:50] + "..."

models.CASCADE這個參數在老版本中是默認值。
on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五個可選擇的值:
CASCADE:此值設置,是級聯刪除;
PROTECT:此值設置,是會報完整性錯誤;
SET_NULL:此值設置,會把外鍵設置爲null,前提是容許爲null;
SET_DEFAULT:此值設置,會把設置爲外鍵的默認值;
SET():此值設置,會調用外面的值,能夠是一個函數。

再次遷移模型Entry:

# python manage.py makemigrations learning_logs# python manage.py migrate


向管理網站註冊模型Entry

# vim learning_logs/admin.py

from django.contrib import adminfrom learning_logs.models import Topic, Entry

admin.site.register(Topic)admin.site.register(Entry)


查看網頁,添加條目

在這裏插入圖片描述

下拉選擇對應的Topic,Text添加任意內容

在這裏插入圖片描述

在這裏插入圖片描述

繼續添加主題Chess的條目,而後再添加主題Rock Climbing的條目

在這裏插入圖片描述


使用Django shell

Django shell用於測試項目及排除項目故障,要退出shell會話,可按Ctr + D。

# python manage.py shell>>> from learning_logs.models import Topic>>> Topic.objects.all()<QuerySet [<Topic: Chess>, <Topic: Rock Climbing>]>

在活動的虛擬環境中執行時,命令python manage.py shell啓動一個Python解釋器,可以使用它來探索存儲在項目數據庫中的數據。

在這裏,咱們導入了模塊learning_logs.models中的模型Topic,而後使用方法Topic.objects.all()來獲取模型Topic的全部實例;它返回的是一個列表,稱爲查詢集(queryset)。

  • 查看分配給每一個主題對象的ID:
>>> topics = Topic.objects.all()>>> for topic in topics:...     print(topic.id, topic)... 
1 Chess
2 Rock Climbing

能夠看到,主題Chess的ID爲1,而Rock Climbing的ID爲2。

  • 獲取任意屬性的值:

知道對象的ID後,就能夠獲取該對象並查看其任何屬性。

>>> t = Topic.objects.get(id=1)>>> t.text'Chess'>>> t.date_added
datetime.datetime(2019, 7, 9, 2, 5, 18, 289746, tzinfo=<UTC>)

  • 查看與主題相關聯的條目:
>>> t.entry_set.all()<QuerySet [<Entry: The opening is thefirst part ofthe game, roughly t...>, <Entry: In the opening phase ofthe game, it's important to...>]>>>> t2 = Topic.objects.get(id=2)>>> t2.entry_set.all()<QuerySet [<Entry: One ofthe most importantconcepts in climbing is to...>]>


建立主頁網頁

使用Django建立網頁的過程一般分三個階段:定義URL、編寫視圖和編寫模板。

首先,你必須定義URL模式。URL模式描述了URL是如何設計的,讓Django知道如何將瀏覽器請求與網站URL匹配,以肯定返回哪一個網頁。每一個URL都被映射到特定的視圖——視圖函數獲取並處理網頁所需的數據。視圖函數一般調用一個模板,後者生成瀏覽器可以理解的網頁。


映射URL

用戶經過在瀏覽器中輸入URL以及單擊連接來請求網頁,所以咱們須要肯定項目須要哪些URL。主頁的URL最重要,它是用戶用來訪問項目的基礎URL。

# vim learning_log/urls.py

from django.contrib import adminfrom django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('learning_logs.urls', namespace='learning_logs')),]

這裏保存完文件以後會報ModuleNotFoundError: No module named 'learning_logs.urls'錯誤,不用理會,繼續往下作。

在文件夾learning_logs中建立另外一個urls.py文件

# vim learning_logs/urls.py

"""定義learning_logs的URL模式"""from django.urls import pathfrom . import views

app_name='learning_logs'urlpatterns = [
    # 主頁
    path('', views.index, name='index'),]


編寫視圖

視圖函數接受請求中的信息,準備好生成網頁所需的數據,再將這些數據發送給瀏覽器——這一般是使用定義了網頁是什麼樣的模板實現的。

# vim learning_logs/views.py

from django.shortcuts import renderfrom .models import Topicdef index(request):
    """學習筆記的主頁"""
    return render(request, 'learning_logs/index.html')

導入了函數render(),它根據視圖提供的數據渲染響應。URL請求與剛纔定義的模式匹配時,Django將在文件views.py中查找函數index(),再將請求對象傳遞給這個視圖函數。

  • 編寫模板:

模板定義了網頁的結構。模板指定了網頁是什麼樣的,而每當網頁被請求時,Django將填入相關的數據。模板讓你可以訪問視圖提供的任何數據。

# mkdir -p learning_logs/templates/learning_logs# vim learning_logs/templates/learning_logs/index.html

<p>Learning Logp><p>Learning Log helps you keep track of your learning, for any topic you're learning about.p>

標籤


標識段落;標籤

指出了段落的開頭位置,而標籤

指出了段落的結束位置。
  • 訪問網頁:

訪問基礎URL——192.168.30.128:8000,能夠看到剛剛定義的模板index.html。

在這裏插入圖片描述


建立其它網頁

在建立完主頁以後,繼續建立兩個顯示數據的網頁,其中一個列出全部的主題,另外一個顯示特定主題的全部條目。對於每一個網頁,咱們都將指定URL模式,編寫一個視圖函數,並編寫一個模板。


模板繼承

建立網站時,幾乎都有一些全部網頁都將包含的元素。在這種狀況下,可編寫一個包含通用元素的父模板,並讓每一個網頁都繼承這個模板。

  • 父模板:首先來建立一個名爲base.html的模板,並將其存儲在index.html所在的目錄中。這個文件包含全部頁面都有的元素;其餘的模板都繼承base.html。
# vim learning_logs/templates/learning_logs/base.html

<p>
  <a href="{% url 'learning_logs:index' %}">Learning Loga>p>{% block content %}{% endblock content %}

第一部分建立一個包含項目名的段落,該段落也是一個到主頁的連接,爲建立連接,咱們使用了一個模板標籤。模板標籤{% url 'learning_logs:index' %}生成一個URL,該URL與learning_logs/urls.py中定義的名爲index的URL模式匹配。

第二部分插入了一對塊標籤。這個塊名爲content,是一個佔位符,其中包含的信息將由子模板指定。

  • 子模板:如今要從新編寫index.html,使其繼承base.html。
# vim learning_logs/templates/learning_logs/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 %},讓Django知道它繼承了哪一個父模板。

而後插入了一個名爲content 的{% block %}標籤,以定義content塊,不是從父模板繼承的內容都包含在content塊中。


顯示全部主題

  • URL模式:

定義顯示全部主題的頁面的URL。

# vim learning_logs/urls.py

"""定義learning_logs的URL模式"""from django.urls import pathfrom . import views

app_name='learning_logs'urlpatterns = [
    # 主頁
    path('', views.index, name='index'),

    # 顯示全部的主題
    path('topics/', views.topics, name='topics'),]

只在用於主頁URL的正則表達式中添加了topics/,Django檢查請求的URL時,這個模式與這樣的URL匹配:基礎URL後面跟着topics。其URL與該模式匹配的請求都將交給views.py中的函數topics()進行處理。

  • 修改視圖:

函數topics()須要從數據庫中獲取一些數據,並將其發送給模板。

# vim learning_logs/views.py

from django.shortcuts import renderfrom .models import Topicdef 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)

函數topics() 包含一個形參:Django從服務器那裏收到的request對象。而後查詢數據庫——請求提供Topic對象,並按屬性date_added對它們進行排序。咱們將返回的查詢集存儲在topics中。

接着定義了一個將要發送給模板的上下文。上下文是一個字典,其中的鍵是咱們將在模板中用來訪問數據的名稱,而值是咱們要發送給模板的數據。在這裏,只有一個鍵—值對,它包含咱們將在網頁中顯示的一組主題。建立使用數據的網頁時,除對象request和模板的路徑外,咱們還將變量context傳遞給render()

  • 編寫模板:

顯示全部主題的頁面的模板接受字典context,以便可以使用topics()提供的數據。

# vim learning_logs/templates/learning_logs/topics.html

{% extends "learning_logs/base.html" %}

{% block content %}  <p>Topicsp>
  
  <ul>
    {% for topic in topics %}      <li>{{ topic }}li>
    {% empty %}      <li>No topics have been added yet.li>
    {% endfor %}  ul>
  {% endblock content %}

首先使用標籤{% extends %}來繼承base.html,接着開始定義content塊。在標準HTML中,項目列表被稱爲無序列表,用標籤

表示。

而後使用一個至關於for循環的模板標籤,它遍歷字典context中的列表topics。在模板中,每一個for循環都必須使用{% endfor %}標籤來顯式地指出其結束位置。

在循環中,要將每一個主題轉換爲一個項目列表項。要在模板中打印變量,須要將變量名用雙花括號括起來。HTML標籤

表示一個項目列表項,在標籤對 內部,位於標籤 和之間的內容都是一個項目列表項。

修改父模板,使其包含到顯示全部主題的頁面的連接:

# vim learning_logs/templates/learning_logs/base.html

<p>
  <a href="{% url 'learning_logs:index' %}">Learning Loga> -  <a href="{% url 'learning_logs:topics' %}">Topicsa>p>{% block content %}{% endblock content %}

在到主頁的連接後面添加了一個連字符-,而後添加了一個到顯示全部主題的頁面的連接,使用的也是模板標籤url。

  • 訪問網頁:

訪問基礎URL——192.168.30.128:8000,能夠看到定義的模板index.html及Topics連接。

在這裏插入圖片描述

點擊Topics連接,查看主題

在這裏插入圖片描述


顯示特定主題頁面

接下來,重複以前步驟,建立一個專一於特定主題的頁面——顯示該主題的名稱及該主題的全部條目。一樣的,咱們將定義一個新的URL模式,編寫一個視圖並建立一個模板。

  • URL模式:

顯示特定主題的頁面的URL模式與前面的全部URL模式都稍有不一樣,由於它將使用主題的id屬性來指出請求的是哪一個主題。

# vim learning_logs/urls.py

"""定義learning_logs的URL模式"""from django.urls import path, re_pathfrom . import views

app_name='learning_logs'urlpatterns = [
    # 主頁
    path('', views.index, name='index'),

    # 顯示全部的主題
    path('topics/', views.topics, name='topics'),

    # 特定主題的詳細頁面
    re_path(r'^topics/(?P\d+)/$', views.topic, name='topic'),]

這裏用到了python正則表達式,/(?P與包含在兩個斜槓內的整數匹配,並將這個整數存儲在一個名爲topic_id的實參中。?P將匹配的值存儲到topic_id中;而表達式\d+與包含在兩個斜杆內的任何數字都匹配,無論這個數字爲多少位。

發現URL與這個模式匹配時,Django將調用視圖函數topic(),並將存儲在topic_id中的值做爲實參傳遞給它。

  • 修改視圖:
# vim learning_logs/views.py

from django.shortcuts import renderfrom .models import Topicdef 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)

第一個除request對象外還包含另外一個形參的視圖函數。這個函數接受正則表達式(?P捕獲的值,並將其存儲到topic_id中。

使用get()來獲取指定的主題,獲取與該主題相關聯的條目,並將它們按date_added排序:date_added前面的減號指定按降序排列,即先顯示最近的條目。將主題和條目都存儲在字典context中,再將這個字典發送給模板topic.html。

  • 編寫模板:
# vim learning_logs/templates/learning_logs/topic.html

{% extends 'learning_logs/base.html' %}

{% block content %}  <p>Topic: {{ topic }}p>

  <p>Entries:p>
  <ul>
  {% for entry in entries %}    <li>
      <p>{{ entry.date_added|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模板:

將顯示示全部主題的頁面中的每一個主題都設置爲連接

# vim learning_logs/templates/learning_logs/topics.html

{% extends "learning_logs/base.html" %}

{% block content %}  <p>Topicsp>

  <ul>
    {% for topic in topics %}      <li>
        <a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}a>
	  li>
    {% empty %}      <li>No topics have been added yet.li>
    {% endfor %}  ul>{% endblock content %}

使用模板標籤url 根據learning_logs中名爲topic的URL模式來生成合適的連接。這個URL模式要求提供實參topic_id,所以在模板標籤url中添加了屬性topic.id

  • 訪問網頁:

在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述

相關文章
相關標籤/搜索