亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Web應用程序學習——《Python編程:從人門到實踐》

系統 1631 0

前言

? ? 在Python越來越火的當下,感覺作為一個計算機專業的學生還是需要掌握一些Python的編程技能。《Python編程:從入門到實踐》是一本好書,我主要學習書里最后的項目部分,因為有C/C++的學習基礎,所以對Python的學習我是想通過實踐,從項目中學習。這段時間打算學習書上這個Web應用程序的項目,Web的相關知識是我沒接觸到的,第一次看到這個項目我并沒有很大的興趣去做,因為怕現在做了之后等到工作的時候其實完全不需要用到,也早忘了。但這段時間,體驗了一些生活,經歷了一些選擇,想在接下來的時間里盡快找到自己以后想做的事,所以想開始做這個項目。沒想到現在再做,已是有興趣,有想探索的心。

此外,我們使用的python是3.6版本,Django是2.1.7,跟書本里的版本不一樣,所以我對部分代碼做了修改以適應我的版本(參考網上的資料)。

?

一、Django和我們的項目

? ? Django是一個Web框架,是一套用于幫助開發交互式網站的工具(Django官網)。Django能夠響應網頁請求,能輕松讀寫數據庫、管理用戶。這個項目將借助Django,在 Windows 下實現一個“學習筆記”的Web應用程序,讓用戶能夠記錄感興趣的主題,并在學習每個主題的過程中添加日志條目。“學習筆記”的主頁對這個網站進行描述,并邀請用戶注冊或登陸。用戶登陸后可創建新主題,添加新條目以及閱讀既有的條目。

二、建立環境

1、要使用Django我們首先需要建立一個虛擬工作環境。

? ? ?? 虛擬環境是系統的一個位置,我們可以在其中安裝包并將其與其他Python的包隔離。這樣做有益于將我們的Web應用程序部署到服務器。

? ? ?? 首先我們為項目建立一個新目錄,并在終端中切換到這個目錄(可以在這個目錄的空白處按住Shift然后點擊右鍵,選擇在Shell中打開目錄)。然后如果是使用Python3,則可以用命令: python -m venv ll_env 創建虛擬環境。(這里是運行了python3的venv模塊,用它來創建一個名為ll_env的虛擬環境);如果不是用Python3則需要先安裝virtualenv包(pip install --user virtualenv),然后用virtualenv ll_env創建虛擬環境。

2、激活虛擬環境

? ? ?? 每次編輯或者使用前都要使用激活命令: ll_env\Scripts\activate 激活后虛擬環境處于活動狀態;要停止虛擬環境,可以使用deactivate命令或者關閉終端。【 Django僅在虛擬環境處于活動狀態時才可用

3、安裝Django

在虛擬環境ll_env目錄下安裝Django: pip install Django

4、在Django中創建項目

使用命令: django-admin startproject learning_log . ? 為Django創建一個名為learning_log的項目。注意命令最后有一個句點'.',有了這個句點可以使我們在部署應用程序時不用遭遇一些配置問題(具體原因我還沒搞懂)

創建的新項目包含了4個文件:

  • settings.py:指定Django如何與系統交互以及管理項目,可以在其中修改/添加一些設置;
  • urls.py:告訴Django應創建 哪些網頁 來響應瀏覽器請求;
  • wsgi.py:幫助Django提供它創建的文件(Web Server Gateway Interface);
  • manage.py:接受命令并將命令交給Django的相關部分去運行,可以用來管理使用數據庫和運行服務器等任務;

5、創建數據庫

執行指令:python manage.py migrate

修改數據庫稱為遷移數據庫,首次執行migrate指令時將讓Django確保數據庫與項目的當前狀態匹配,且將新建一個數據庫。

6、查看項目

執行指令:python manage.py runserver

可以核實Django是否正確地創建了項目。該指令啟動了一個服務器,可以查看系統中的項目,了解它們的工作情況。

指令的運行結果會返回三種信息:

  • 確認是否正確創建了項目(System check identified no issues);
  • 指出Django的版本以及當前使用的設置文件的名稱;
  • 指出項目的URL(URL為本地計算機localhost時,只處理當前系統發出的請求,而不允許其他人查看你正在開發的網頁服務器)

三、創建應用程序

Django項目是由一系列應用程序組成的,它們協同工作,使項目成為一個整體。

創建應用程序的指令為:python manage.py startapp "appname"。該指令建立了應用程序所需的基礎設施:創建了文件名為appname的文件夾,包含了model.py、admin.py和views.py。

  • model.py:定義應用程序中管理的數據;
  • admin.py:
  • views.py:

1、定義模型

對于本次項目,每位用戶都需要在學習筆記中創建很多主題,用戶輸入的每個條目都與特定的主題相關聯并以文本形式顯示。

在model.py中,首先應該導入models模塊: from django.db import models 每個模型都要繼承自models.Model

我們創建的模型是在告訴Django如何處理應用程序中存儲的數據,在代碼層面,模型就是一個類:

            
              class Topic(models.Model):
    '''用戶學習的主題'''
    
    #設置文本屬性
    #text:由字符或文本組成的數據,需要存儲少量的文本(名稱、標題等)
    #CharField表示設置字符串字段,需要預設要最大長度
    text = models.CharField(max_length=200)
    
    #設置時間戳
    #DateTimeField用于記錄日期和時間的數據
    #有兩個bool型參數:auto_now表示保存時自動設置該字段為當前時間(最后修改日期)
    #auto_now_add表示當對象第一次被創建時自動設置該字段為當前日期(創建時間戳)
    date_added = models.DateTimeField(auto_now_add=True)

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

__str__(self)告訴Django默認應使用哪個屬性來顯示有關主題的信息,Django將調用該函數來顯示模型的簡單表示。

2、激活模型

要使用模型必須讓Django將應用程序包含到項目中,我們通過修改項目目錄下的settings.py添加應用程序:

在settings.py中有一個INSTALLED_APPS的列表,表示該Django項目是由哪些應用程序組成的,我們在其中添加我們自己的應用程序名稱即可。

            
              #INSTALLED_APPS是一個列表,告訴Django項目是由哪些應用程序組成的
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    #我的應用程序
    'learning_logs',

]
            
          

然后我們要修改數據庫使其能夠存儲與模型Topic相關的信息,修改數據庫的命令如下:

python manage.py makemigrations learning_logs (該命令讓Django確定該如何修改數據庫使其能夠存儲與我們定義的新模型相關聯的數據;該命令會創建一個遷移文件,這個文件將在數據庫中為模型Topic創建一個表)

python manage.py migrate (該命令實現真正的數據庫遷移)

因此每當需要修改項目管理的數據時,都需要三個步驟:

  • 修改models.py
  • 對learning_logs(應用程序名)調用makemigrations
  • 執行遷移指令migrate

3、Django管理網站

Django提供了管理網站(admin site)來方便處理模型。網站的管理員可以使用管理網站,但普通用戶不能使用。

1.創建超級用戶

超級用戶是具備所有權限的用戶。權限限制了用戶的可執行操作。在Django中創建超級用戶的命令為:

python manage.py createsuperuser

隨后你將需要輸入用戶名、電子郵件地址(可以為空)和密碼(需要輸入兩遍)

Django并不存儲你輸入的密碼,而是存儲從該密碼派生出來的一個字符串——散列值。每當輸入密碼時Django計算其散列值并將結果與存儲的散列值進行比較,如果兩個結果相同則通過驗證。這種做法確保了密碼的安全。

2.向管理網站注冊模型

Django自動在管理網站中添加了一些模型,如User和Group,對于我們自己創建的模型則需要手工注冊。

在我們創建應用程序learning_logs時,Django在models.py所在的目錄中自動創建了一個名為admin.py的文件,我們需要在該文件中添加我們的模型。

            
              from django.contrib import admin    #自動創建時已有的代碼

from learning_logs.models import Topic#導入我們注冊的模型
admin.site.register(Topic) 
            
          

所以向管理網站注冊模型的步驟為:

  • 先從應用程序中導入要注冊的模型;
  • 再使用admin.site.register向管理網站注冊我們的模型;

4、定義模型Entry

每個條目與特定的主題相關聯,是多對一的關系。

            
              class Entry(models.Model):
    '''在學習的有關某個主題的知識'''
    #下面的代碼將每個條目(entry)關聯到特定的主題。每個主題創建時都給它分配了一個鍵(ID)
    #需要在兩項數據之間建立聯系時,Django使用與每項信息相關聯的鍵
    
    #ForeignKey:外鍵,是一個數據庫術語,引用了數據庫中的另一條記錄
    #django2.0之后,定義外鍵和一對一關系的時候需要加on_delete選項,此參數為了避免兩個表里的數據不一致的問題
    #一般情況下使用models.CASCADE:級聯刪除
    topic = models.ForeignKey(Topic,on_delete=models.CASCADE)

    #text是一個TextField實例,不需要限制長度,可創建一個可編輯文本框
    text = models.TextField()

    #date_added讓我們能夠按創建順序呈現條目,并在每個條目旁邊放置時間戳
    date_added = models.DateTimeField(auto_now_add=True)

    class Meta:
        '''存儲用于管理模型的額外信息'''
        #設置verbose_name_plural屬性,讓Django在需要時使用Entries來表示多個條目
        #如果沒有這個類,Django將使用Entrys來表示多個條目
        verbose_name_plural = 'entries'
    
    def __str__(self):
        '''返回模型的字符串表示'''
        #如果條目包含的文本過長,則我們只顯示前50個字符
        if len(self.text) > 50:
            return self.text[:50] + '...'
        else:
            return self.text
            
          

因此定義的步驟為:

  • 將條目與主題相關聯:topic = models.ForeignKey(Topic,on_delete=models.CASCADE)
  • 創建可編輯文本框:text = models.TextField()
  • 按時間戳順序呈現條目:date_added = models.DateTimeField(auto_now_add=True)
  • 內嵌Meta類,存儲用于管理模型的額外信息;
  • __str__(self):模型的表示

定義好Entry模型后進行遷移,遷移完成后向管理網站注冊Entry,按照上面講過的步驟。

由此可知,創建新模型的步驟為:

  • 定義新模型
  • 遷移數據庫
  • 向管理網站注冊新模型

5、Django shell

輸入一些數據后就可以通過交互式終端會話以編程方式查看這些數據了,可以用來測試項目、排除故障。

python manage.py shell (開啟shell)

from learning_logs.models import Topic (導入模型Topic,來測試Topic)

Topic.objects.all() (獲取模型Topic的所有實例,返回一個列表稱為查詢集)

每個主題對象有一個ID,有屬性text表示主題的名稱、date_added表示時間戳。

我們還可以查看與主題相關聯的條目,Entry中定義了外鍵topic,由這個外鍵獲取數據,可以使用模型的小寫名稱+下劃線+單詞“set”,如topic.entry_set.all()獲取各條目。

四、創建網頁

使用Django創建網頁的過程通常分為三個階段:定義URL、編寫視圖和編寫模板。

  • 定義URL:讓Django知道如何將瀏覽器請求與網站URL匹配,以確定返回哪個網;
  • 編寫視圖:每個URL都被映射到特定的視圖,視圖函數獲取并處理網頁所需的數據。視圖函數通常調用一個模板,后者生成瀏覽器能夠理解的網頁。

1、映射URL

用戶通過在瀏覽器中輸入URL以及單擊鏈接來請求網頁,因此我們需要確定項目需要哪些URL,這將通過在urls.py文件中添加URL實現。

項目主文件夾learning_log中的文件urls.py:

            
              #導入為項目和管理網站管理URL的函數和模塊
from django.contrib import admin
from django.urls import path,include

#urlpatterns包含了項目中應用程序的URL
#admin.site.urls定義了可在管理網站中請求的所有URL
urlpatterns = [
    path('admin/', admin.site.urls),
    #下面中的實參namespace將learning_logs的URL同項目中其他URL區分開
    path('',include('learning_logs.urls',namespace='learning_logs')),
    
]
            
          

path('',include('learning_logs.urls',namespace='learning_logs')) : 使項目包含了模塊learning_logs.urls,然后我們需要在文件夾learning_logs中創建另一個urls.py文件,該urls.py中將URL映射到視圖。

            
              from django.urls import path
from . import views    #在當前目錄導入視圖
#數據庫中的視圖:把多個表連接起來形成一個新的表

app_name = 'learning_logs'

#urlpatterns包含了應用程序learning_logs中請求的網頁
urlpatterns = [
    #path的參數:第一個參數是路由(一個匹配URL的準則),通常可為'';
    #第二個參數指定了要調用的視圖函數,視圖函數接受請求中的信息,準備好生成網頁所需的數據,再將這些數據發送給瀏覽器
    #第三個參數是將這個URL模式的名稱指定為index,這樣每當需要提供到這個主頁的鏈接時我們可以直接使用這個名稱而不用編寫URL
    #主頁
    path('',views.index,name='index'),
   
]
            
          

兩個urls.py的區別是,前者添加了應用程序的所有URL,后者指定應用程序各URL對應的視圖。

2、編寫視圖

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

視圖函數編寫在views.py中,該文件是創建應用程序(python manage.py startapp)時自動生成的。

下面是本項目主頁的視圖。

            
              from django.shortcuts import render #render渲染:根據信息創建一個網頁

#request為請求對象
def index(request):
    #render的兩個實參:原始請求對象 以及 一個可用于創建網頁的模板
    #模板定義了網頁的結構
    return render(request,'learning_logs/index.html')
            
          

3、編寫模板

視圖對應的模板是html文件,定義了網頁的結構,指定了網頁是什么樣的, 每個模板對應一個網頁 。為了使項目結構規范,我們在應用程序的目錄下新建一個目錄templates,然后再新建一個目錄名為learning_logs(與應用程序名稱相同)的目錄,將往后所有模板都保存于此。

編寫模板用到的是HTML標簽,也可能需要用到CSS或者javascript這些前端常用語言。

初始的index.html文件如下:

            
              

Learning Log

你想在主頁上顯示的話

標簽用于指示一個段落的開始和結束。

4、模板的繼承

創建網站時幾乎都有一些所有網頁都將包含的元素,這種情況下我們可以編寫一個包含通用元素的父模板,并讓每個網頁都繼承這個模板,而不必在每個網頁中重復定義這些通用元素。

父模板base.html:

所有頁面都包含的元素只有頂端的標題,我們將在每個頁面中包含這個模板。

將標題設置為到主頁的鏈接。

            
              

Learning Log

{% block content %}{% endblock content %}

模板標簽{% %}:一小段代碼,生成要在網頁中顯示的信息。其中的url 'learning_logs:index'生成了一個URL,該URL與learning_logs/urls.py中定義的名為index的URL模式匹配,其中learning_logs表示一個命名空間,index表示該命名空間中一個獨特的URL模式。

link text :錨定義標簽,用于定義鏈接。結合模板標簽可以使得鏈接容易保持最新。link text表示鏈接顯示出來的文本。

塊標簽{% block content %}{% endblock content %}:這個塊的名稱為centent,該代碼中的塊是一個占位符,其包含的內容由子模版決定。

子模版index.html:

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

{% block content %}

              

Learning Log

你想在主頁上顯示的話

{% endblock content %}

{% extends "learning_logs/base.html" %}:表示繼承了父模板base.html;

這樣看來使用模板繼承簡化了每個模板的代碼編寫,也便于管理項目。

5、顯示所有主題的頁面

1.URL模式

首先應該定義顯示所有主題的頁面的URL,用于指出網頁對應的視圖。

            
              from django.urls import path
from . import views    #在當前目錄導入視圖
#數據庫中的視圖:把多個表連接起來形成一個新的表

app_name = 'learning_logs'

#urlpatterns包含了應用程序learning_logs中請求的網頁
urlpatterns = [
    #path的參數:第一個參數是路由(一個匹配URL的準則),通常可為'';
    #第二個參數指定了要調用的視圖函數,視圖函數接受請求中的信息,準備好生成網頁所需的數據,再將這些數據發送給瀏覽器
    #第三個參數是將這個URL模式的名稱指定為index,這樣每當需要提供到這個主頁的鏈接時我們可以直接使用這個名稱而不用編寫URL
    #主頁
    path('',views.index,name='index'),

    #URL與該模式匹配的請求都將交給views.py中的函數topics()處理
    path('topics/',views.topics,name='topics'),
]
            
          

相比于主頁的path,我們在正則表達式中添加了“topics/”,Django檢查請求的URL時這個模式與這樣的URL匹配。與該模式匹配的URL都將交給視圖函數topics處理(位于views.py中)

2.視圖

            
              def topics(request):
    '''顯示所有主題'''
    
    #按屬性date_added排序
    topics = Topic.objects.order_by('date_added')

    #將要發送給模板的上下文(字典型),其中的鍵是我們將在模板中用來訪問數據的名稱,
    #而值是我們要發送給模板的數據
    context = {'topics':topics}
    
    return render(request,'learning_logs/topics.html',context)
            
          

上面的視圖需要數據交互,具體步驟為:

  • topics = Topic.objects.order_by('date_added'):查詢數據庫獲取所有Topic對象,按時間戳排序。
  • context = {'topics':topics}:定義將要發送給模板的上下文。其中的context表示將要發送給模板的上下文(字典型數據,鍵是模板中用來訪問數據的名稱,值是要發送給模板的數據)。
  • return render(request,'learning_logs/topics.html',context):渲染網頁。創建使用數據的網頁時,除對象request和模板的路徑之外,還需要context(上下文)。

3.模板

顯示所有主題的頁面 的模板 接受字典context。在專門存放模板的目錄下新建文件topics.html:

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

{% block content %}

    
              

Topics

    {% for topic in topics %}
  • {{ topic }}
  • {% empty %}
  • No topics have been added yet.
  • {% endfor %}
{% endblock content%}
    • 標簽:表示無序的項目列表
    • {% for topic in topics %}:相當于for循環的模板標簽,遍歷了字典context中的列表topics,并以{% endfor %}指出循環的結尾
    • 標簽:表示一個項目列表項,位于
        標簽內
      • {{topic}}要在模板中打印變量需要將變量名用 雙花括號 括起來
      • {% empty %}:告訴Django在列表topics為空時該怎么辦

      然后修改父模板使其包含到顯示所有主題的頁面的鏈接

                          
                            

      Learning Log - Topic

      {% block content %}{% endblock content %}

      注意上面兩個錨標簽之間有連字符“-“,這使得兩個鏈接顯示在用一行且中間有不屬于鏈接的連字符顯示出來。

      6、顯示特定主題的頁面

      接下來創建一個專注于特定主題的頁面,用于顯示該主題的名稱以及該主題的所有條目。同樣的,我們需要定義一個新的URL模式,編寫一個視圖并創建一個模板。

      1.URL模式

      顯示特定主題的頁面的URL模式與前面的所有URL模式都稍有不同,因為這是用主題的ID屬性來指出請求的哪個主題。

      在learning_logs目錄下的urls.py中添加下面URL:

                          
                                #特定主題的詳細頁面:http://localhost:8000/topics/1/
          #/(?P
                            
                              \d+)/與包含在兩個斜杠內的整數匹配(如上,為1),并將這個整數存儲在一個名為topic_id的實參中
          #()括號捕獲了URL中的值,?P
                              
                                將匹配的值存儲到topic_id中;
          #\d+與包含在兩個斜桿內的任何數字都匹配,不管這個數字為多少位
          #當發現URL與這個模式匹配時,Django將調用視圖函數topic(),并將topic_id傳給它
      
          path('topics/(?P
                                
                                  \d+)/',views.topic,name='topic'),
                                
                              
                            
                          
                        

      上面用了較為復雜的正則表達式,正則表達式我覺得是熟能生巧。

      2.視圖

                          
                            def topic(request,topic_id):
          '''顯示單個主題及其所有的條目'''
          
          #topic和entries被稱為查詢,向數據庫查詢特定的信息,可以先在Django shell中查詢
          topic = Topic.objects.get(id=topic_id)
          
          #根據topic查詢與其相關的所有條目(外鍵)
          entries = topic.entry_set.order_by('-date_added')#減號表示降序,使得先顯示最新的條目
          
          context = {'topic':topic,'entries':entries}
          
          return render(request,'learning_logs/topic.html',context)
                          
                        

      視圖函數的參數必須包含request,也可以包含其他參數,如上面函數包含了topic_id。該函數接受URL模式中正則表達式捕獲的整數值并將其存儲在topic_id中。

      3.模板

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

      Topics:{{ topic }}

      Entries:

        {% for entry in entries %}
      • {{ entry.date_added|date:'M d, Y H:i' }}

        {{ entry.text|linebreaks }}

      • {% empty %}
      • No topics have been added yet.
      • {% endfor %}
      {% endblock content%}

      注意到視圖中我們在渲染網頁時傳遞了context參數,其包含了topic和entries,所以在模板中我們可以以這兩個參數為變量。

      在Django模板中,豎線“|”表示模板過濾器,是對模板變量的值進行修改的函數,指示出后面是過濾器。

      過濾器date: 'M d, Y H:i'表示以“月 日,年 時:分”的格式顯示時間。

      過濾器linebreaks將包含換行符的長條目轉為瀏覽器能夠理解的格式,以免顯示為一個不間斷的文本塊。

      然后我們將顯示所有主題的頁面中的每個主題都設置為鏈接:(修改topics.html)

                          
                            --snip--
      {% for topic in topics %}
          
                            
    • {{ topic }}
    • {% empty %} --snip--

      這里的每個topic對應不同的鏈接,所以我們需要向模板標簽傳遞參數topic指出具體的話題,url 'learning_logs:topic' 與 urls.py文件中定義的URL模式?path('topics/(?P \d+)/',views.topic,name='topic') 相對應,并且該模式要求提供實參,為此我們在模板標簽url中添加了屬性topic.id(對應URL模式中的參數topic_id)。而topic.id是每個話題存進數據庫時擁有的序號。

      五、部分小結

      至此,我們學習了如何使用Django框架來創建Web應用程序。

      首先我們需要指定項目規范,明確項目流程,要有條理有目的。開始項目前要搭建虛擬環境,在虛擬環境中安裝Django,然后創建一個項目。一個項目是由一個或多個應用程序構成的,因此我們需要在項目中創建應用程序,然后定義表示應用程序數據的模型(model),包括了數據的類型以及顯示方式等屬性,另外對于某些數據我們還可能需要設置外鍵,使其與另一種數據相關聯。

      此外我們還簡單學習了Django的數據庫。我們對項目模型修改后都需要遷移數據庫,這可以直接在shell上通過兩條遷移命令完成。將數據存放在數據庫之后我們可以通過查詢數據庫來獲取數據,如Topic.objects.get(id=topic_id)是通過話題的ID來獲取話題對象。

      我們還學習了如何創建可訪問管理網站的超級用戶,并且每次創建新模型后我們需要向管理網站注冊新模型。

      較為重要的,我們學習了創建網頁的具體步驟:創建URL模式->編寫視圖->編寫模板。URL模式是網頁地址到視圖的映射,視圖決定了網頁的內容和功能,模板根據視圖提供的內容決定網頁的樣子。其中包含了后端的知識和前端的知識,雖然只是皮毛,但已經讓我們對Django編寫Web程序的思路有一個大致的了解。

      六、用戶賬戶

      Web應用程序的核心是讓任何用戶都能夠注冊賬戶并能夠使用它。所以我們應該創建一些表單,讓用戶能夠添加主題和條目以及編輯既有的條目。同時需要防范對基于表單的網頁發起的常見攻擊。

      此外我們還需要實現一個用戶身份驗證系統,為此我們將創建一個注冊頁面供用戶創建賬戶,并讓有些頁面只能供已登錄的用戶訪問。

      七、讓用戶能夠輸入數據

      當前只有超級用戶能夠通過管理網站輸入數據,我們將使用Django的表單創建工具來創建讓用戶能夠輸入數據的頁面,這樣用戶就不用與管理網站交互。

      1、添加新主題

      創建基于表單的頁面的方法幾乎與前面創建網頁一樣:定義一個URL,編寫一個視圖函數并編寫一個模板。主要差別在于 需要導入包含表單的模塊forms.py

      1.用于添加主題的表單

      讓用戶輸入并提交信息的頁面都是表單。用戶輸入信息時我們要進行驗證,確認提供的信息是正確的數據類型且不是惡意信息(如中斷服務器的代碼)。然后我們再對有效的信息進行處理并將其保存到數據庫的合適地方。(這些工作很多都是由Django自動完成的)

      在Django中創建表單的最簡單方式是使用 ModelForm ,它根據我們之前定義的模型的信息自動創建表單。為此我們在與models.py相同的目錄下新建一個forms.py的文件來編寫表單。

                          
                            from django import forms
      from .models import Topic,Entry
      
      class TopicForm(forms.ModelForm):
          #Meta高數Django根據哪個模型創建表單以及表單中包含哪些字段
          #我們根據Topic模型創建一個表單,該表單只包含字段text
          class Meta:
              model = Topic
              fields = {'text'}
              labels = {'text':''}    #讓Django不要為字段text生成標簽
                          
                        
      • 首先必須導入Django的forms模塊,而且也要導入我們已經定義的模型Topic、Entry;
      • 每個表單是一個繼承了forms.ModelForm的類,最簡單的ModelForm版本只包含一個內嵌的Meta類,它告訴Django根據哪個模型創建表單以及在表單中包含哪些字段。
      • model=Topic:根據模型Topic創建一個表單;
      • fields={'text'}:表單只包含字段text;

      2.定義添加新主題的URL模式

      在learning_logs/urls.py中

                          
                            #用于添加新主題的網頁
      path('new_topic/',views.new_topic,name='new_topic')
                          
                        

      3.編寫視圖函數new_topic()

                          
                            from django.shortcuts import render #render渲染:根據信息創建一個網頁
      from django.http import HttpResponseRedirect,Http404
      from django.urls import reverse
      
      from .models import Topic
      from .forms import TopicForm
      
      --snip--
      def new_topic(request):
          '''添加新主題'''
      
          if request.method != 'POST':    #未提交數據則創建一個新表單
              form = TopicForm()          #創建一個新表單
          else:                           #對POST提交的數據進行處理
              form = TopicForm(request.POST)  #用戶輸入的數據存儲在POST中
              if form.is_valid():         #核實用戶是否填寫了所有必不可少的字段且輸入符合要求
                  form.save()             #保存表單到數據庫
                  return HttpResponseRedirect(reverse('learning_logs:topics'))
          context = {'form':form}         #將表單通過上下文字典發送給模板
          return render(request,'learning_logs/new_topic.html',context)
                          
                        

      GET和POST:

      Web應用程序用到兩種主要請求類型GET請求和POST請求:

      從服務器讀取數據的頁面使用GET請求;在用戶需要通過表單提交信息時,通常使用POST請求。

      所以用戶請求的是空表單時服務器發送的是GET請求,用戶要求對填寫好的表單進行處理時服務器發送的是POST請求。

      此外,HttpResponseRedirect類用于用戶提交主題后將用戶重定向到網頁Topics。函數reverse()的作用是根據指定的URL模式確定URL。

      要將提交的信息保存到數據庫必須先檢查它們是否有效:form.is_valid()。該函數核實用戶填寫了所有必不可少的字段且輸入的數據與要求的字段類型一致。

      這里順便說說對渲染和重定向的簡單理解,網頁的渲染我們用了render函數,這是在創建一個新的網頁;而重定向我們使用了HttpResponseRedirect類,這是跳轉到之前已經創建過的網頁。

      4.new_topic模板的編寫

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

      Add a new topic

      {% csrf_token %} {{ form.as_p }}
      {% endblock content %}
      • 標簽定義了一個HTML表單,action告訴服務器將提交的表單數據要發送到哪里。這里我們將表單發回給視圖函數new_topic(),method讓瀏覽器以POST的請求方式提交數據。
      • csrf_token模板標簽用于防止攻擊者利用表單來獲得對服務器未經授權的訪問;CSRF(跨站點偽造請求)
      • form.as_p中的修飾符as_p是讓Django以段落的格式渲染所有表單元素。

      5.鏈接到頁面new_topic

      在頁面topics中添加一個到頁面new_topic的鏈接。(topics.html文件中)

                          
                            
                              Add a new topic:
                            
                          
                        

      2、添加新條目

      添加新條目的流程還是一樣:定義URL模式、編寫視圖函數、編寫模板,然后鏈接到添加新條目的網頁。但再次之前我們需要在forms.py中添加一個新的條目的類,表示條目的表單。

      1.用于添加新條目的表單

      創建一個與模型Entry相關聯的表單(forms.py):

                          
                            from django import forms
      from .models import Topic,Entry
      
      --snip--
      
      class EntryForm(forms.ModelForm):
          class Meta:
              model = Entry
              fields = {'text'}
              labels = {'text':''}
              #widgets(小部件)是一個HTML表單元素,如單行文本框等
              #forms.Textarea將文本區域設置為80列
              widgets = {'text':forms.Textarea(attrs={'cols':80})}
                          
                        

      2.URL模式new_entry

      條目必須與特定的主題相關聯:(urls.py)

                          
                            path('new_entry/(?P
                            
                              \d+)/',views.new_entry,name='new_entry')
                            
                          
                        

      3.視圖函數new_entry()

                          
                            --snip--
      from .forms import TopicForm,EntryForm
      
      --snip--
      
      def new_entry(request,topic_id):
          '''在特定的主題中添加新條目'''
          
          #從數據庫根據主題的ID獲取特定主題
          topic = Topic.objects.get(id=topic_id)
          
          if request.method != 'POST':
              form = EntryForm()    #未提交數據,創建一個空表單
          else:
              #根據POST提交的數據對數據進行處理
              form = EnrtyForm(date=request.POST)
              #表單內容是否有效
              if form.is_valid():
                  new_entry = form.save(commit=False)
                  new_entry.topic = topic
                  new_entry.save()
                  #條目內容有效則創建新條目后回到主題頁面
                  return HttpResponseRedirect(reverse('learning_logs:topic',args=[topic_id]))
          
          #GET請求或者POST請求的內容無效 則根據表單內容創建新頁面
          context = {'topic':topic,'form':form}
          return render(request,'learning_logs/new_entry.html',context)
                          
                        
      • EntryForm(data=request.POST):創建了一個以request對象中的POST數據來填充的EntryForm實例;
      • form.save(commit=False):Django創建一個新的條目對象并將其存儲到new_entry中但不保存到數據庫,然后設置條目對于的主題為當前的主題然后再將新條目保存到數據庫——new_entry.save()
      • new_entry.topic = topic:這里new_entry對象有topic屬性,是因為new_entry是EntryForm的實例,EntryForm表單使用了Entry模型,而Entry模型含有topic這個外鍵屬性。
      • reverse('learning_logs:topic',args=[topic_id]):args是一個包含了要包含在URL中的所有實參。

      4.模板new_entry

      new_entry.html:

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

      {{topic}}

      Add a new entry:

      {% csrf_token %} {{ form.as_p }} {% endblock content %}

      5.鏈接到頁面new_entry

      在顯示特定主題的頁面中添加到頁面new_entry的鏈接:(topic.html)

                          
                            
                              add new entry
                            
                          
                        

      3、編輯條目

      創建一個讓用戶能夠編輯既有條目的頁面。

      1.定義URL模式edit_entry

                          
                            --snip--
      urlpatterns=[
          --snip--
          path('edit_entry/(?P
                            
                              \d+)/',views.edit_entry,name='edit_entry')
      ]
                            
                          
                        

      2.視圖函數edit_entry()

      頁面edit_entry收到GET請求時將返回一個表單,讓用戶能夠對條目進行編輯;收到POST請求時它將修改后的文本保存到數據庫中(veiws.py):

                          
                            --snip--
      
      def edit_entry(request,entry_id):
          '''編輯既有的條目'''
          entry = Entry.objects.get(id=entry_id)#獲取需要修改的條目對象以及相關的主題
          topic = entry.topic
      
          if request.method != 'POST':
              #初次請求時創建一個表單并使用當前條目填充表單:顯示條目的現有信息
              form = EntryForm(instance=entry)
          else:
              form = EntryForm(instance=entry,data=request.POST)
      
              if form.is_valid():
                  form.save()
                  return HttpResponseRedirect(reverse('learning_logs/topic',args=[topic.id]))
      
          context = {'entry':entry,'topic':topic,'form':form}
          return render(request,'learning_logs/edit_entry.html',context)
                          
                        

      form = EntryForm(instance=entry,data=request.POST):讓Django根據既有條目對象創建一個表單實例,并根據request.POST中的相關數據對其進行修改。(這樣則做到就當前條目的修改)

      3.模板edit_entry

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

      {{topic}}

      Edit entry:

      {% csrf_token %} {{ form.as_p }}
      {% endblock content %}

      依次顯示了返回當前主題的鏈接、Edit entry、編輯條目的表單、提交表單的按鈕。

      在標簽{% url %}中將條目ID作為一個實參讓視圖對象能夠修改正確的條目對象。

      4.鏈接到頁面edit_entry

      topic.html:

                          
                            
                              edit entry
                            
                          
                        

      將上面的鏈接放在每個條目的日期和文本后面(在循環中)。

      4、創建用戶賬戶

      我們將建立一個用戶注冊和身份驗證系統,讓用戶能夠注冊賬戶,進而可以登錄賬戶和注銷賬戶。我們將創建一個新的應用程序,其中包含與處理用戶賬戶相關的所有功能。我們還需要修改Topic模型,讓每個主題歸屬特定用戶。

      1.應用程序users

      還記得創建應用程序的命令嗎?

                          
                            python manage.py startapp users
                          
                        

      這樣就新建了一個名為users的目錄,其結構與應用程序learning_logs相同。

      然后我們需要將應用程序users添加到setting.py中

                          
                            --snip--
      INSTALLED_APPS = [
          --snip--
          #我的應用程序
          'learning_logs',
          'users',
      ]
      
                          
                        

      接著我們還需要修改項目根目錄中的urls.py,使其包含我們將為應用程序users定義的URL:(urls.py)

                          
                            #導入為項目和管理網站管理URL的函數和模塊
      from django.contrib import admin
      from django.urls import path,include
      
      #urlpatterns包含了項目中應用程序的URL
      #admin.site.urls定義了可在管理網站中請求的所有URL
      urlpatterns = [
          path('admin/', admin.site.urls),
          #users的URL
          path('users/',include('users.urls',namespace='users')),
          #下面中的實參namespace將learning_logs的URL同項目中其他URL區分開
          path('',include('learning_logs.urls',namespace='learning_logs')),
          
      ]
                          
                        

      2.登錄頁面

      實現登錄頁面的功能時,我們使用的是Django提供的默認登錄視圖,因此URL模式會稍有不同。在learning_log/users/中新建一個名為urls.py的文件,然后添加下面代碼:

                          
                            '''為應用程序users定義URL模式'''
      
      from django.urls import path 
      from django.contrib.auth.views import LoginView
      from . import views
      
      LoginView.template_name = 'users/login.html'
      app_name = 'users'
      
      urlpatterns =[
          #登錄頁面
          #導入視圖login,使得登錄頁面的URL模式與'http://localhost:8000/users/login/'匹配
          #'template_name':'users/login.html'告訴Django去哪里查找我們將編寫的模板
          #視圖實參為login,使Django使用默認視圖login,而不是views.login
          path('login/',LoginView.as_view(),name='login'),
      ]
      
      
                          
                        

      LoginView是Django的默認登錄視圖,因此我們需要指明該視圖對應的模板:LoginView.template_name = 'users/login.html'

      模板login.html,需要放在loearning_log/users/template/users目錄下,同前面的learning_logs:

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

      Log in to your account.

      {% if form.errors %}

      Your username and password didn't match. Please try again.

      {% endif %}
      {% csrf_token %} {{ form.as_p }}
      {% endblock content %}

      使用了模板標簽的if來處理表單錯誤的情況。我們要讓登錄視圖處理表單,因此將實參action設置為登錄頁面的URL。登錄視圖將一個表單發送給模板,在模板中我們顯示這個表單并添加一個提交按鈕。

      此外我們的模板還包好了一個隱藏的表單元素‘next’,其中的實參value告訴Django在用戶成功登錄后將其重定向到主頁。

      然后我們在base.html中添加到登錄頁面的鏈接,讓所有頁面都包含它:(base.html)

                          
                            --snip--
      
                            
                              Topics
                            
                            -
      
      {% if user.is_authenticated %}
          Hello,{{ user.username }} .
      {% else %}
          
                            
                              log in
                            
                            
      {% endif %}
      
      
                          
                        

      user.is_authenticated表示用戶是否已經登錄,若登錄則不顯示登錄鏈接。

      這里可以發現使用了Django自帶的視圖時,我們對用戶的屬性操作可以直接使用user.屬性,其中is_authenticated表示用戶是否已經登錄,username直接返回用戶名。

      3.注銷頁面

      在users/urls.py中添加注銷的URL模式:

                          
                            #注銷功能
      path('logout/',views.logout_view,name="logout"),
                          
                        

      自己編寫視圖函數logout_view():

                          
                            from django.shortcuts import render
      from django.http import HttpResponseRedirect
      from django.urls import reverse
      from django.contrib.auth import logout,login,authenticate
      from django.contrib.auth.forms import UserCreationForm
      
      def logout_view(request):
          '''注銷用戶'''
          #直接調用django.contrib.auth中的Logout函數注銷用戶
          logout(request)
          return HttpResponseRedirect(reverse("learning_logs:index"))
                          
                        

      這個視圖很簡單,直接調用了Django的logout函數,該函數將request對象作為實參然后重定向到主頁。

      然后我們在base.html鏈接到注銷視圖并使用if模板標簽使得只有在用戶已經登錄的情況下才可以進行注銷:

                          
                            --snip--
      {% if user.is_authenticated %}
          Hello,{{ user.username }} .
          
                            
                              log out
                            
                            
      {% else %}
          
                            
                              log in
                            
                            
      {% endif %}
      --snip--
                          
                        

      4.注冊頁面

      創建新用戶注冊頁面,我們將使用Django提供的表單UserCreationForm,然后自己編寫視圖和模板。

      首先還是先定義URL模式:

                          
                            #注冊頁面
      path('register/',views.register,name='register'),
                          
                        

      然后編寫視圖函數register():

      我們需要顯示一個空的注冊表單,并在用戶提交填寫好的注冊表單時對其進行處理。如果注冊成功,這個函數還需要讓用戶自動登錄。

                          
                            from django.contrib.auth import logout,login,authenticate
      from django.contrib.auth.forms import UserCreationForm
      
      def register(request):
          '''注冊新用戶'''
          if request.method != 'POST':
              form = UserCreationForm()
          else:
              form = UserCreationForm(data=request.POST)
              #檢查用戶輸入的數據是否有效:是否包含非法字符,輸入的兩個密碼是否相同
              #以及用戶有沒有試圖做惡意的事
              if form.is_valid():
                  #save返回新創建的用戶對象
                  new_user = form.save()
                  #用戶注冊時被要求輸入密碼兩次,當表單是有效時兩個密碼相同,所以任取其中一個:password1
                  #用戶名和密碼無誤時authenticate將返回一個通過了身份驗證的用戶對象
                  authenticated_user = authenticate(username=new_user.username,
                  password=request.POST['password1'])
                  #login登錄函數,需要一個HttpRequest對象和一個用戶對象
                  login(request,authenticated_user)
                  return HttpResponseRedirect(reverse('learning_logs:index'))
          context = {'form':form}
          return render(request,'users/register.html',context)
                          
                        
      • UserCreationForm:默認的用戶注冊表單,該表單保存后其用戶名和密碼的散列值保存到數據庫中,save函數同時也返回了一個新創建的用戶對象。
      • 根據要響應的是否是POST請求區分用戶將要填寫注冊信息或者用戶已經填好注冊信息然后提交;
      • 保存信息后讓用戶自動登錄需要兩個步驟:首先調用authenticate函數,實參為用戶名username和用戶密碼request.POST['password1'](因為用戶注冊時被要求輸入兩次密碼,所以是password1,也可以是password2因為兩個密碼是一樣的)。若用戶名和密碼匹配則該函數會返回一個通過了身份驗證的用戶對象。然后我們調用函數login()并將request對象和通過了身份驗證的用戶對象作為實參傳遞給它讓用戶登錄。最后將用戶重定向到主頁。

      編寫注冊模板register.html:

                          
                            {% extends "learning_logs/base.html" %}
      
      {% block content %}
        
                                                  
      {% csrf_token %} {{ form.as_p}}
      {% endblock content%}

      鏈接到注冊頁面:(base.html)

                          
                            --snip--
      {% if user.is_authenticated %}
          Hello, {{ user.username }}
          
                            
                              log out
                            
                            
      {% else %}
          
                            
                              register
                            
                            -
          
                            
                              log in
                            
                            
      {% endif %}
      --snip--
                          
                        

      至此,已登錄的用戶將看到問候語和注銷鏈接,而未登錄的用戶將看到注冊鏈接和登錄鏈接。

      5、讓用戶擁有自己的數據

      我們將創建一個系統,確定各項數據所屬的用戶,再限制對頁面的訪問,讓用戶只能使用自己的數據。

      1.使用@login_required限制訪問

      Django提供了 裝飾器@login_required 限制用戶的訪問權限,對于某些頁面只允許已登錄的用戶訪問它們。裝飾器是放在函數定義前面的指令,Python在函數運行前根據裝飾器來修改函數代碼的行為。

      首先我們限制用戶對topics頁面的訪問,每個主題都歸特定用戶所有,因此只允許已登錄的用戶請求topics頁面,為此,在learning_logs/views.py中添加下面代碼:

                          
                            --snip--
      from django.contrib.auth.decorators import login_required
      --snip--
      
      @login_required
      def topics(request):
          --snip--
                          
                        

      需要先導入login_required函數,然后在要限制的視圖函數前加上一行@login_required,這樣的話Python在允許topics()的代碼前會先允許login_required()的代碼,而login_required()會檢查用戶是否已登錄,僅當用戶已登錄時Django才會運行topics()。若用戶未登錄,我們需重定向到登錄頁面(通過修改learning_log/settings.py):

                          
                            '''
      項目learning_log的Django設置
      '''
      
      --snip--
      #我的設置
      LOGIN_URL = '/users/login/'
                          
                        

      如果未登錄的用戶請求裝飾器@login_requeired的飽和頁面,Django將重定向到settings.py中的LOGIN_URL指定的URL。

      2.全面限制用戶對整個項目的訪問

      根據上面的方式給其他需要保護的頁面添加裝飾器。對于此項目,我們將不限制對主頁、注冊頁面和注銷頁面的訪問,并限制對其他所有頁面的訪問。所以learning_logs/views.py中對除index()外的每個視圖都應用了裝飾器:

                          
                            --snip--
      @login_required
      def topic(request,topic_id):
          --snip--
      
      @login_required
      def new_topic(request):
          --snip--
      
      ...
                          
                        

      3.將數據關聯到用戶

      我們只需要將最高層的數據關聯到用戶,這樣更低層的數據將自動關聯到用戶 。例如在本項目中最高層數據是主題,所以有條目都與特定主題相關聯,只要每個主題都歸屬于特定用戶,我們就能確定數據庫中每個條目的所有者。

      為此我們需要修改模型Topic,在其中添加一個關聯到用戶的外鍵(A關聯到B的外鍵——可以認為A是屬于B的),然后對數據庫進行遷移,最后對部分視圖進行必要的修改,使其只顯示與當前用戶有關聯的信息。

                          
                            --snip--
      from django.contrib.auth.models import User
      
      class Topic(models.Model):
          --snip--
          owner = models.ForeignKey(User)
                          
                        

      先導入User模型再設置外鍵。

      在遷移數據庫之前我們先確定當前有哪些用戶(獲取用戶ID)。這我們可以在Django shell下執行命令查看:

                          
                            python manage.py shell
      
      >>>from django.contrib.auth.models import User
      >>>User.objects.all()
      [
                            
                              ,
                              
                                ,...]
      
      >>>for user in User.objects.all():
      ...    print(user.username,user.id)
      ...
      ll_admin 1
      username userid
      >>>
                              
                            
                          
                        

      其中ll_admin是超級用戶。

      知道了用戶ID后我們再遷移數據庫:

                          
                            (命令)python manage.py makemigrations learning_logs
      (回應)You are trying to add a non_nullable field 'owner' to topic without a default;
           we can't do that (the database needs something to populate existing rows).
           Please select a fix:
           1) Provide a one-off default now (will be set on all existing rows)
           2) Quit, and let me add a default in models.py
           Select an option: 1 (輸入1)
      (回應)Please enter the default value now, as valid Python
           The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now()
      >>> 1(輸入1,超級用戶ID)
      (回應) Migrations for 'learning_logs':
             0003_topic_owner.py:
              - Add field owner to topic
                          
                        

      執行makemigrations命令后Django指出我們試圖給既有模型Topic添加一個必不可少的字段但這個字段沒有默認值,所以Django

      給我們提供了兩種選擇:現在提供默認值,或者退出后在models.py中添加默認值。我們選擇前者并將所有既有主題都關聯到超級用戶ll_admin(用戶ID:1),并非必須是超級用戶,我們也可以使用已創建的任何用戶。現在我們可以執行遷移了:

                          
                            python manage.py migrate
                          
                        

      ?如果你想驗證遷移符合預期,可在shell會話中像下面這樣做:

                          
                            >>> from learning_logs.models import Topic
      >>> for topic in Topic.objects.all():
      ...    print(topic,topic.owner)
      ...
      (返回主題以及所屬的用戶名)
      >>>
                          
                        

      這樣順便提一下重構數據庫的做法:執行命令python manage.py flush,這將重建數據庫結構,然后需要重新創建超級用戶,且原來的數據全部丟失。

      4.只允許用戶訪問自己的主題

      在views.py中對topics()做修改:

                          
                            --snip--
      @login_required
      def topics(request):
          '''顯示所有的主題'''
          topics = Topic.objects.filter(owner=request.user).order_by('date_added')
          context = {'topics':topics}
          return render(request,'learning_logs/topics.html', context)
      --snip--
                          
                        

      ?request對象有一個user屬性,存儲了有關該用戶的信息,我們使用filter只從數據庫中獲取owner屬性為當前用戶的Topic對象,然后按'date_added'的方式排序。

      5.保護用戶的主題

      我們還沒有限制對顯示單個主題的頁面的訪問。以擁有所有主題的用戶的身份登錄,訪問特定的主題,并復制該頁面的URL,或將其中的ID記錄下來。然后注銷并用另一個用戶的身份登錄,再輸入剛才復制的URL,這時依然能查看該主題中的條目。

      為了修復這種問題,我們在視圖函數topic()獲取請求的條目前執行檢查:(views.py)

                          
                            from Django.http import HttpResponseRedirect, Http404
      
      @login_required
      def topic(request,topic_id):
          '''顯示單個主題及其所有的條目'''
          topic = Topic.objects.get(id=topic_id)
          #確認請求的主題屬于當前用戶
          if topic.owner != request.user:
              raise Http404
          entries = topic.entry_set.order_by('-date_added')
          context = {'topic':topic,'entries':entries}
          return render(request,'learning_logs/topic.html',context)
                          
                        

      服務器上沒有請求的資源時標準的做法是返回404響應。,所以我們導入了Http404,并在用戶請求它不能查看的主題時引發這個異常,而判斷用戶是否有權查看請求的主題,則看topic.owner(主題所屬用戶)和request.user(發出請求的用戶)是否為同一個用戶。

      topic.entry_set是利用了外鍵獲取話題對應的所有條目;-date_added使得先顯示最新的條目。

      6.保護頁面edit_entry

      這個也跟上面一樣。(view.py)

                          
                            --snip--
      @login_required
      def edit_entry(request,entry_id):
          '''編輯既有條目'''
          entry = Entry.objects.get(id=entry_id)
          topic = entry.topic    
          
          if topic.owner != request.user:
              raise Http404
      
          if request.method != 'POST':
              --snip--
      
          
                          
                        

      同樣是判斷用戶身份是否匹配。上面的entry.topic是在模型中定義的Entry的外鍵。

      7.將新主題關聯到當前用戶

      即創建新主題的時候必須指定其owner字段的值。由于我們可以通過request對象獲得當前用戶,所以可以直接將新主題關聯到當前用戶。(views.py)

                          
                            @login_required
      def new_topic(request):
          '''添加新主題'''
          
          if request.method != 'POST':
              form = TopicForm()
      
          else:
              form = TopicForm(request.POST)
              if form.is_valid():
                  new_topic = form.save(commit=False)
                  
                  new_topic.owner = request.user    #指定主題所屬的用戶
                  
                  new_topic.save()
                  
                  return HttpResponseRedirect(reberse('learning_logs:topics'))
          
          context = {'form':form}
          return render(request,'learning_logs/new_topic.html',context)
      
                          
                        

      form.save()獲取一個新主題對象后才可以設置這個新主題所屬的用戶。

      6、用戶系統小結

      至此我們基本完成了一個小用戶系統,雖然比較簡單,但有基本的功能。我們賦予了每個用戶特定的權限。且我們添加了注冊、登錄和注銷功能。這一過程我們用了很多Django自帶模塊和函數。如Django提供的表單UserCreationForm讓用戶能夠創建新賬戶。建立簡單的用戶身份驗證和注冊系統后我們通過使用裝飾器@login_required禁止未登錄的用戶訪問特定頁面。我們還通過外鍵將數據關聯到特定用戶。同時為了讓用戶只能看到屬于他的數據,我們使用方法filter()來獲取屬于用戶自己的數據。

      此外我們還知道了如何將請求的數據的所有者同當前登錄的用戶進行比較。

      八、總結

      通過上面的學習我覺得已經可以基本了解到如何用Django編寫Web應用程序:定義URL模式、編寫對應的視圖、編寫視圖對應的模板。同時也可以學到一點對Django自帶的數據庫的基本操作以及Web應用程序與數據庫的聯系。但其中的小細節和一些知識點需要認真學習并理解后自己才真正會用。而且通過這一系列的學習我覺得我自己也對Web應用程序有了一定認識,但要達到熟悉的程度的話還需要多練多做項目,實踐出真知。

      順便說說,其實這篇文章的大概前5%是我第一次學習Django時寫的,那時沒堅持寫下去,只顧看書打代碼。現在因為一些原因需要用到Django,所以利用這次的復習我把這篇文章完善。我覺得寫文章還是挺好的,幫助自己記憶,并且寫的時候我常會想要怎樣寫出自己的理解,這一思考過程往往會給我新的啟發。

      ?

      ?

      ?

      ?

      ?

      ?


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 色综合久久中文字幕综合网 | 久青草国产高清在线视频 | 青青久久国产成人免费网站 | 精品伊人久久大香线蕉网站 | 福利在线观看视频 | xxxx免费观看 | 精品久久一区二区三区 | 日韩欧美综合在线二区三区 | 淫视频网站| 精品推荐 国产 | 日韩精品中文字幕视频一区 | 鲁啊鲁啊鲁在线视频播放 | 91免费精品国自产拍在线不卡 | 国产性色视频在线高清 | 国产精品日本一区二区在线播放 | 亚洲精品视频在线看 | 中文字幕有码在线观看 | 欧美成人专区 | yellow中文字幕久久网 | 性一交一乱一视频免费看 | 奇米第四色首页 | 国产精品久久久久一区二区 | 国产精品天堂 | 国产精品久久久久久久久99热 | 91精品国产福利尤物免费 | 久草视频福利在线观看 | 国产一级精品视频 | 精品伊人| 日日噜噜夜夜狠狠视频无 | 四虎影视成人精品 | 综合玖玖 | 愉拍自拍| 国内精品久久久久丫网址 | a4yy私人毛片 | 99热97| 久久国产精品99久久久久久老狼 | 亚洲在线欧美 | 久久人视频 | 日本一区二区在线播放 | 国产一级特黄aa级特黄裸毛片 | 欧美一级免费看 |