1. 程式人生 > >Django專案——簡單筆記本V1

Django專案——簡單筆記本V1

一 程式碼結構

二 專案配置

1 learning_log/settings.py

# -*- coding: utf-8 -*-

import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

SECRET_KEY = 'make_your_own_secret_key'

DEBUG = True

ALLOWED_HOSTS = []

'''
這是一個元組,告訴 Django 專案是由哪些應用程式組成的。
'''
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 通過將應用程式編組,在專案不斷增大,包含更多的應用程式時,有助於對應用程式進行跟蹤。
    # 這裡新建了一個名為 My apps 的片段,當前它只包含應用程式 learning_logs 。
    # 我的應用程式
    'learning_logs',
)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
)

ROOT_URLCONF = 'learning_log.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'learning_log.wsgi.application'

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# 中文
LANGUAGE_CODE = 'zh_Hans'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

STATIC_URL = '/static/'

2 learning_log/urls.py

# -*- coding: utf-8 -*-
# 匯入了為專案和管理網站管理 URL 的函式和模組
from django.conf.urls import include, url
from django.contrib import admin
# 這個檔案的主體定義了變數 urlpatterns
# 變數 urlpatterns 包含專案中的應用程式的 URL
urlpatterns = [
    # 包含模組 admin.site.urls ,該模組定義了可在管理網站中請求的所有 URL 。
    url(r'^admin/', include(admin.site.urls)),
    # 我們添加了一行程式碼來包含模組 learning_logs.urls 。
    # 這行程式碼包含實參 namespace ,讓我們能夠將 learning_logs 的 URL 同項目中的其他 URL 區分開來,
    # 這在專案開始擴充套件時很有幫助。
    url(r'', include('learning_logs.urls', namespace='learning_logs')),
]

三 後端程式碼 

1 模型(learning_logs/models.py)

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models

'''
模型就是一個類,包含屬性和方法。
'''
'''
使用者學習的主題
Model:Django 中一個定義了模型基本功能的類。
屬性 text 是一個 CharField,由字元或文字組成的資料.需要儲存少量的文字,如名稱、標題或城市時,可使用 CharField 。
屬性 date_added 是一個 DateTimeField,記錄日期和時間的資料
傳遞了實參 auto_add_now=True ,每當使用者建立新主題時,這都讓 Django 將這個屬性自動設定成當前日期和時間。
欄位參考: https://docs.djangoproject.com/en/1.8/ref/models/fields/
'''
class Topic(models.Model):
    """A topic the user is learning about."""
    text = models.CharField(max_length=200)
    date_added = models.DateTimeField(auto_now_add=True)
    # 預設應使用哪個屬性來顯示有關主題的資訊。
    # 如果你使用的是 Python 2.7 ,應呼叫方法 __unicode__() ,而不是 __str__()
    def __unicode__(self):
        """Return a string representation of the model."""
        return self.text

"""
學到的有關某個主題的具體知識
"""
class Entry(models.Model):
    '''
    第一個屬性 topic 是一個 ForeignKey 例項
    外來鍵是一個數據庫術語,它引用了資料庫中的另一條記錄;這些程式碼將每個條目關聯到特定的主題。
    每個主題建立時,都給它分配了一個鍵(或 ID )。
    需要在兩項資料之間建立聯絡時, Django 使用與每項資訊相關聯的鍵。
    根據這些聯絡獲取與特定主題相關聯的所有條目。
    '''
    topic = models.ForeignKey(Topic)
    # 這種欄位不需要長度限制,因為我們不限制條目的長度。
    text = models.TextField()
    # 屬性 date_added 讓我們能夠按建立順序呈現條目,並在每個條目旁邊放置時間戳。
    date_added = models.DateTimeField(auto_now_add=True)
    '''
    在 Entry 類中嵌套了 Meta 類。
    Meta 儲存用於管理模型的額外資訊
    它讓我們能夠設定一個特殊屬性,讓 Django 在需要時使用 Entries 來表示多個條目。
    如果沒有這個類, Django 將使用 Entrys 來表示多個條目。
    '''
    class Meta:
        verbose_name_plural = 'entries'

    '''
    由於條目包含的文字可能很長,我們讓 Django 只顯示 text 的前 50 個字元
    我們還添加了一個省略號,指出顯示的並非整個條目。
    '''
    def __unicode__(self):
        """ 返回模型的字串表示 """
        return self.text[:50] + "..."

2 檢視(learning_logs/views.py)

# -*- coding: utf-8 -*-
'''
檢視函式接受請求中的資訊,準備好生成網頁所需的資料,再將這些資料傳送給瀏覽器
'''
from django.shortcuts import render
# 匯入了與所需資料相關聯的模型
from .models import Topic

def index(request):
    """ 學習筆記的主頁
    URL 請求與我們剛才定義的模式匹配時, Django 將在檔案 views.py 中查詢函式 index() ,再將請求物件傳遞給這個檢視函式。
    在這裡,我們不需要處理任何資料,因此這個函式只包含呼叫 render() 的程式碼。
    這裡向函式 render() 提供了兩個實參:原始請求物件以及一個可用於建立網頁的模板。
    """
    return render(request, 'learning_logs/index.html')

# 函式 topics() 包含一個形參: Django 從伺服器那裡收到的 request 物件
def topics(request):
    """顯示所有主題"""
    # 我們查詢資料庫 —— 請求提供 Topic 物件,並按屬性 date_added 對它們進行排序。
    # 我們將返回的查詢集儲存在 topics 中。
    topics = Topic.objects.order_by('date_added')
    # 我們定義了一個將要傳送給模板的上下文。
    # 上下文是一個字典,其中的鍵是我們將在模板中用來訪問資料的名稱,而值是我們要傳送給模板的資料。
    # 在這裡,只有一個鍵 — 值對,它包含我們將在網頁中顯示的一組主題。
    context = {'topics': topics}
    # 建立使用資料的網頁時,除物件 request 和模板的路徑外,我們還將變數 context 傳遞給 render()
    return render(request, 'learning_logs/topics.html', context)

'''
這是第一個除 request 物件外還包含另一個形參的檢視函式。
這個函式接受正則表示式 (?P<topic_id>\d+) 捕獲的值,並將其儲存到 topic_id 中。
我們使用 get() 來獲取指定的主題
我們獲取與該主題相關聯的條目,並將它們按 date_added 排序:
date_added 前面的減號指定按降序排列,即先顯示最近的條目。
我們將主題和條目都儲存在字典 context 中,再將這個字典傳送給模板 topic.html。
在自己的專案中編寫查詢時,先在 Django shell 中進行嘗試大有裨益。
相比於編寫檢視和模板,再在瀏覽器中檢查結果,在 shell 中執行程式碼可更快地獲得反饋。
'''
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)

3 url配置(learning_logs/urls.py)

# -*- coding: utf-8 -*-
"""
定義 learning_logs 的 URL 模式
匯入了函式 url ,因為我們需要使用它來將 URL 對映到檢視
"""
from django.conf.urls import url
# 句點讓 Python 從當前的 urls.py 模組所在的資料夾中匯入檢視。
from . import views
# 這個檔案的主體定義了變數 urlpatterns
# 變數 urlpatterns 是一個列表,包含可在應用程式 learning_logs 中請求的網頁
'''
實際的 URL 模式是一個對函式 url() 的呼叫,這個函式接受三個實參。
第一個是一個正則表示式。 Django 在 urlpatterns 中查詢與請求的 URL 字串匹配的正則表示式,因此正則表示式定義了 Django 可查詢的模式。
我們來看看正則表示式 r'^$' 。其中的 r 讓 Python 將接下來的字串視為原始字串,而引號告訴 Python 正則表示式始於和終於何處。
脫字元( ^ )讓 Python 檢視字串的開頭,而美元符號讓 Python 檢視字串的末尾。
總體而言,這個正則表示式讓 Python 查詢開頭和末尾之間沒有任何東西的 URL 。
Python 忽略專案的基礎 URL ( http://localhost:8000/ ),因此這個正則表示式與基礎 URL 匹配。
其他 URL 都與這個正則表示式不匹配。如果請求的 URL 不與任何 URL 模式匹配, Django 將返回一個錯誤頁面。
url() 的第二個實參指定了要呼叫的檢視函式。請求的 URL 與前述正則表示式匹配時, Django 將呼叫 views.index.
第三個實參將這個 URL 模式的名稱指定為 index ,讓我們能夠在程式碼的其他地方引用它。
每當需要提供到這個主頁的連結時,我們都將使用這個名稱,而不編寫 URL 。
'''
urlpatterns = [
    # 主頁.
    url(r'^$', views.index, name='index'),
    
    # 顯示所有主題.
    url(r'^topics/$', views.topics, name='topics'),
    
    # 特定主題詳細頁面
    # r 讓 Django 將這個字串視為原始字串,並指出正則表示式包含在引號內。
    # 這個表示式的第二部分( /(?P<topic_id>\d+)/ )與包含在兩個斜槓內的整數匹配,並將這個整數儲存在一個名為 topic_id 的實參中。
    # 這部分表示式兩邊的括號捕獲 URL 中的值; ?P<topic_id> 將匹配的值儲存到 topic_id 中;
    # 而表示式 \d+ 與包含在兩個斜杆內的任何數字都匹配,不管這個數字為多少位。
    #  URL 與這個模式匹配時, Django 將呼叫檢視函式 topic() ,並將儲存在 topic_id 中的值作為實參傳遞給它。
    # 在這個函式中,我們將使用 topic_id 的值來獲取相應的主題。
    url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),
]

4 管理(learning_logs/admin.py)

# -*- coding: utf-8 -*-
from django.contrib import admin
# 匯入我們要註冊的模型
from learning_logs.models import Topic, Entry

# 讓 Django 通過管理網站管理我們的模型
admin.site.register(Topic)
admin.site.register(Entry)

四 前端程式碼

1 learning_logs/templates/learning_logs/base.html

<!--
建立網站時,幾乎都有一些所有網頁都將包含的元素。
在這種情況下,可編寫一個包含通用元素的父模板,並讓每個網頁都繼承這個模板,而不必在每個網頁中重複定義這些通用元素。
這種方法能讓你專注於開發每個網頁的獨特方面,還能讓修改專案的整體外觀容易得多。
這個檔案包含所有頁面都有的元素;其他的模板都繼承 base.html 。
當前,所有頁面都包含的元素只有頂端的標題。我們將在每個頁面中包含這個模板,因此我們將這個標題設定為到主頁的連結:
這個檔案的第一部分建立一個包含專案名的段落,該段落也是一個到主頁的連結。
為建立連結,我們使用了一個 模板標籤 ,它是用大括號和百分號表示的。
模板標籤是一小段程式碼,生成要在網頁中顯示的資訊。
在這個例項中,模板標籤 {% url 'learning_logs:index' %} 生成一個 URL ,該 URL 與 learning_logs/urls.py 中定義的名
為 index 的 URL 模式匹配。
在這個示例中, learning_logs 是一個 名稱空間 ,而 index 是該名稱空間中一個名稱獨特的 URL 模式。
-->
<p>
  <a href="{% url 'learning_logs:index' %}">學習筆記</a> -
  <a href="{% url 'learning_logs:topics' %}">主題</a>
</p>
<!--
我們插入了一對塊標籤。這個塊名為 content ,是一個佔位符,其中包含的資訊將由子模板指定。
子模板並非必須定義父模板中的每個塊,因此在父模板中,可使用任意多個塊來預留空間,而子模板可根據需要定義相應數量的塊。
-->
{% block content %}{% endblock %}
<!--
在大型專案中,通常有一個用於整個網站的父模板 ——base.html ,且網站的每個主要部分都有一個父模板。
每個部分的父模板都繼承 base.html ,而網站的每個網頁都繼承相應部分的父模板。
這讓你能夠輕鬆地修改整個網站的外觀、網站任何一部分的外觀以及任何一個網頁的外觀。
這種配置提供了一種效率極高的工作方式,讓你樂意不斷地去改進網站。
-->

2 learning_logs/templates/learning_logs/index.html

<!--
可發現我們將標題 Learning Log 替換成了從父模板那裡繼承的程式碼。
子模板的第一行必須包含標籤extends  ,讓Django 知道它繼承了哪個父模板。
檔案 base.html 位於資料夾 learning_logs 中,因此父模板路徑中包含 learning_logs 。
這行程式碼匯入模板 base.html 的所有內容,讓 index.html 能夠指定要在 content 塊預留的空間中新增的內容。
-->
{% extends "learning_logs/base.html" %}
<!--
模板定義了網頁的結構。模板指定了網頁是什麼樣的,而每當網頁被請求時, Django 將填入相關的資料。模板讓你能夠訪問檢視提供的任何資料。
我們的主頁檢視沒有提供任何資料,因此相應的模板非常簡單。
建立網頁的過程看起來可能很複雜,但將 URL 、檢視和模板分離的效果實際上很好。
這讓我們能夠分別考慮專案的不同方面,且在專案很大時,讓各個參與者可專注於其最擅長的方面。
例如,資料庫專家可專注於模型,程式設計師可專注於檢視程式碼,而 Web 設計人員可專注於模板。
們插入了一個名為 content 的 block 標籤,以定義 content 塊。
不是從父模板繼承的內容都包含在 content 塊中,在這裡是一個描述專案 “ 學習筆記 ” 的段落。
我們使用標籤 endblock 指出了內容定義的結束位置。
-->
{% block content %}
  <p>學習筆記,記錄你的學習過程!</p>
{% endblock content %}

3 learning_logs/templates/learning_logs/topic.html

<!--
首先使用標籤 extends 來繼承 base.html
-->
{% extends 'learning_logs/base.html' %}

{% block content %}

  <p>Topic: {{ topic }}</p>

  <p>Entries:</p>
  <ul>
    <!--
    每個專案列表項都將列出兩項資訊:條目的時間戳和完整的文字。為列出時間戳,我們顯示屬性 date_added 的值。
    在 Django 模板中,豎線( | )表示模板過濾器 ——對模板變數的值進行修改的函式。
    過濾器 date: 'M d, Y H:i' 以這樣的格式顯示時間戳: January 1, 2015 23:00 。
    接下來的一行顯示 text 的完整值,而不僅僅是 entry 的前50 個字元。
    過濾器 linebreaks 將包含換行符的長條目轉換為瀏覽器能夠理解的格式,以免顯示為一個不間斷的文字塊。
    我們使用模板標籤 empty 列印一條訊息,告訴使用者當前主題還沒有條目。
    -->
  {% for entry in entries %}
    <li>
      <p>{{ entry.date_added|date:'M d, Y H:i' }}</p>
      <p>{{ entry.text|linebreaks }}</p>
    </li>
  {% empty %}
    <li>
      沒有針對該主題的條目。
    </li>
  {% endfor %}
  </ul>

{% endblock content %}

4 learning_logs/templates/learning_logs/topics.html

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

{% block content %}

  <p>主題</p>

  <ul>
    <!--在模板中,每個 for 迴圈都必須使用 endfor 標籤來顯式地指出其結束位置。
    我們使用模板標籤 url 根據 learning_logs 中名為 topic 的 URL 模式來生成合適的連結。
    這個 URL 模式要求提供實參 topic_id ,因此我們在模板標籤 url 中添加了屬性 topic.id。
    現在,主題列表中的每個主題都是一個連結,連結到顯示相應主題的頁面,如 http://localhost:8000/topics/1/ 。
    -->
    {% for topic in topics %}
      <li>
        <a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a>
      </li>
    <!--模板標籤  empty  ,它告訴 Django 在列表 topics 為空時該怎麼辦-->
    {% empty %}
      <li>還沒有新增主題</li>
    {% endfor %}
  </ul>

{% endblock content %}

三 管理介面演示

四 測試演示