Python-Django

Thursday, Nov 21, 2024 | 11 minute read | Updated at Thursday, Nov 21, 2024

@
Python-Django

使用 Django 框架建立網站

Django

Django 是什麼呢?在Django 官網的介紹:

Django 是一個高階 Python Web 框架,鼓勵快速開發和簡潔、務實的設計。它由經驗豐富的開發人員構建,解決了 Web 開發的大部分麻煩,因此您可以專注於編寫應用程序,而無需重新發 ​​ 明輪子。它是免費且開源的。

Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. Built by experienced developers, it takes care of much of the hassle of web development, so you can focus on writing your app without needing to reinvent the wheel. It’s free and open source.

簡單來說就是一個框架,相較 Flasks 能處理更大型的專案。

安裝

(上課 11-21 上午最後半小時)
*開啟虛擬環之後,輸入下面的指令便可以安裝 Django (macOS)

python -m pip install Django==5.1.3

建立專案

1.輸入下面的指令開啟專案: 注意要在資料夾名稱後面加.才不會開在資料夾裡面

django-admin startproject mysite(file-name) .

2.文件裡面會生出一個檔案manage.py 執行它

python manage.py

3.在終端機列出來的 list 可以看到一個 runserver,執行 runserver

python manage.py runserver

4.成功執行的話會出現一段文字,裡面會有路徑Starting development server at http://127.0.0.1:8000/,如果8000這個 port 開啟不了話,我們可以自己指定一個 port 給它,用下面的指令執行:

python manage.py runserver 8888

8888這個是自己設定的,也可以換別的數字。

5.cmd+click 進入網頁,成功連接的話會看到下面的綠色火箭 成功頁面

6.這步驟可以跳過,在設定改預設語言為中文,在setting.py裡找這個

LANGUAGE_CODE = 'en-us' #預設
LANGUAGE_CODE = 'zh-Hant' #繁中

建立分頁

1.在urls裡的預設路徑

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

'admin/'代表網址列顯示的名字http://127.0.0.1:8000/admin/
admin.site.urls表示這個頁面要執行什麼,為了方便管理,會拆出來放在另一個一資料夾

(上課 1121 下午)

2.設定自己的路徑

urlpatterns = [
    path('/index', index),
]

from django.http import HttpResponse
#這個HttpResponse是傳送回應給瀏覽器看
def index(request):
   return HttpResoponse("index page")

3.把def拆出來放在另一個資料夾views.py方便日後做管理。
usrl.py

from django.contrib import admin
from django.urls import path
from .views import index

urlpatterns = [
    path('admin/', admin.site.urls),
    path('/index', index, name="index"),
]

views.py

from django.http import HttpResponse

def index(resquest):
    return HttpResponse("Start Writting Your Resume")

4.建立 Template 在最外層新增一個資料夾:Templates,在setting.py裡把檔案掛到的DIRS[]這樣系統才會從這個資料夾裡面找檔案
setting.py

DIRS["Templates"]

views.py設定render讓網頁渲染頁面
views.py

from django.http import HttpResponse
from django.shortcuts import render

def index(resquest):
    return render(request,"home.html")

home.html放在剛建立的Templates資料夾裡面

5.html 設定:

  • <header>重複志訓可以建立一個公版,之後使用 {% extend "資料夾路徑" %}匯入。

  • 挖洞:在公版用{% block "自己取名字" %}{% endblock %}挖洞,之後的檔案在同樣的指令中放置要顯示的內容
    公版

    {% block "自己取名字" %} {% endblock %}
    

    檔案

    {% block "自己取名字" %}
    
    <h1>XXXXX</h1>
    <p>nuo;bjkncdjfpenvjfl/e;nfvu oe'n jf/vfe</p>
    
    {% endblock %}
    

MVC vs MTV

在軟體架構模式中,普遍使用 MVC 模式(Model–view–controller),它把軟體系統分為三個基本部分:模型(Model)、視圖(View)和控制器(Controller)。
在這邊是由控制器(Controller)來決定使用者看的畫面。

MVC

MVC中文圖 MVC英文圖

MTV

而在 Django 裡的為 MTV 模式 (Modle-Template-View),是由 Template 決定使用者看的畫面 Django MTV 兩者差別在看法不一樣,所以設計角度不一樣。

建立 app

一個專案裡面可以有很多個app應用程式(功能)

口訣:MTV+U

1.建立 app 指令:

python manage.py startapp app_file_name

2.新增urls.py並建立 path

from django.urls import path
from .views import home

urlpatterns = [
    path("",home),
]

這邊可以直接幫路徑取名字,方便之後再 html 連結時,可以快速的使用命名替代路徑作為連結的依據。

app_name = "app_file_name"
urlpatterns = [
    path("",home, name="xxx"),
]
<a herf=" {% url 'app_file_name:xxx'%}"></a>

3.在views.py建立

from django.shortcuts import render

def home(request):
    return render(request,"app_file_name/home.html")

4.建立 template 資料夾,放 html 檔。
放在 app 的template資料夾目前還沒有連動,要在setting.py裡將檔案掛在 APP 下

INSTALLED_APPS = [
  "app_file_name"
]

5.建立網頁要渲染的 html 檔

6.在專案資料夾的urls.py加入 path

from django.urls import path,include

path("app_file_name/", include("app_file_name.urls"))

使用inclide代表連接app_file_name資料夾裡urls.py的連結。

7.確定是否正確連接http://127.0.0.1:8000/app_file_name/,若是沒有,看錯誤訊息改正就可以完成。

執行步驟 list

基本的五步驟,若是有出現錯誤訊息,除了依據錯誤訊息改正之外,也可照下面步驟做確認

  • M “T” V+U: 新增Template資料夾
  • MT “V” +U: views.py定義要執行的內容
  • MTV+ “U”: 設定路徑path
  • app 登記在setting.py裡面的INSTALLED_APPS
  • 在根目錄(最外層的urls.py)登記 app 入口路徑

路徑命名 REST

REST 全名 Representational State Transfer( 表現層狀態轉移),統一的命名方式,他是一種設計風格,並不是一種標準。但目前業界普遍採用這種設計。

資源 GET PUT POST DELETE
一組資源的 URI,比如https://example.com/resources 列出 URI,以及該資源組中每個資源的詳細資訊(後者可選)。 使用給定的一組資源替換當前整組資源。 在本組資源中建立/追加一個新的資源。 該操作往往返回新資源的 URL。 刪除整組資源。
單個資源的 URI,比如https://example.com/resources/142 取得指定的資源的詳細資訊,格式可以自選一個合適的網路媒體類型(比如:XML、JSON 等) 替換/建立指定的資源。並將其追加到相應的資源組中。 把指定的資源當做一個資源組,並在其下建立/追加一個新的元素,使其隸屬於當前資源。 刪除指定的元素。

建立 Model

Model 主要在決定表單資料的框架。
我們設計表單的架構,給使用者填入資料。

Model

model.py建立表格需要的欄位

from django.db import models

class Resume (models.Model):
    title = models.CharField(max_length=50)
    skill = models.CharField(max_length=200)
    content = models.TextField(null=True)

使用.CharField``TextField設定為文字欄位

方法 用途 參數/預設
.CharField() 文字輸入框 (max_length=50)
.TextField() 文字輸入區 (null=True)

每個執行方法會有不同的預設,跑不動時可以看是不是需要的參數沒有放
如果要設定必填(null=False),讓使用者填有必要的就好。

makemigration

當 modle 的框架建立好之後,在建立資料庫之前,必須先做 Migration(遷移)

python manage.py makemigrations

執行完成會生出一個新的migrations資料夾裡面會紀錄所有執行 makemigration的步驟

(.venv) Joanna@hanedahinase Django Practice % python manage.py makemigrations
Migrations for 'resumes':
  resumes/migrations/0001_initial.py
    + Create model Resume

這時候並還沒有執行,只是先建立描述檔。

在描述檔裡,會自動生成id

 ('id', models.BigAutoField(
    auto_created=True,
    primary_key=True,
    serialize=False,
    verbose_name='ID'))

這個是系統為了抓資料,自動幫資料編號的指令

migrate

1.建好描述檔之後,在執行migrate

python manage.py migrate

2.這時候在根目錄的檔案db.sqlite裡面就會建好剛剛設定的 model 目前裡面的檔案是以位元組的方式呈現,要在 VS Code 裡面看到可讀的檔案,要加外掛SQLite Viewer 這樣點進檔案就可以看到東西了!

3.我們可以根據描述檔的編號,去復原動作

python manage.py migrate app_file_name 0001

要小心在以建立資料庫的情況下,刪除欄位會將裡面的資料也一起刪除,所以刪除時要很小心。
如果要看 migration 的狀態,可以執行showmigration查看列表

4.從終端機新增資料進去,看看是否設定都正確
進到 Shell 裡新增資料:指令python manage.py shell

>>> from resumes.models import Resumes
>>> Joanna = Resumes()
>>> Joanna.title = "CEO"
>>> Joanna.save()

“edditing eara below”

CRUD

Creat 建立

1.在 html 設定表單

form method="POST" action="{% url '路徑名稱'%}"></form>

<form method="POST"method 指用什麼方法action="{% url 'resumes:new' %}"action 指送到哪裡
HTML 的 form 目前的版本只有POST GET兩種方法,如果沒有寫的話,預設是 get,對自己送

2.為防止 CSRF(Cross Site Request Forgery)跨站請求偽造 ,會需要 CSRF token,在檔案中的form插入指令

<form>{% csrf_token %}</form>

這個指令會讓系統生成序號,確認這個送出表單是從本站被送出,沒有經過第三方傳送。

Read 讀取

1.從from action="{ url '接收路徑' }"得到表單資料後,將表單寫入資料庫
view.py設定:

def index(request):
    if request.POST:
        #準備寫入資料庫
        resume = Resume()
        resume.title = request.POST.get("title")
        resume.skill = request.POST.get("skill")
        resume.content = request.POST.get("content")
        resume.save()

        return HttpResponse("get information")

這時候從網頁新增的資料,就會在db.sqlite裡面出了。

2.接下來要讀取資料views.py,然後在頁面上顯示出來index.html
views.py檔案

def index(request):
    if request.POST:
     .
     .
     .
        return HttpResponse("get information")
    #讀取列表
    resumes = Resume.objects.all()
    return render(request,"index.html",{"resumes":resumes})

Resume.objects.all()抓出寫入 Resume 的所有物件
{"resumes":resumes}字典 在index.html檔案

<ul>
  {% for resume in resumes %}
  <li>{{ resume.title }}</li>
  {% endfor %}
</ul>

目前在畫面上可以看到資料 List 囉

3.建立一個新的頁面來顯示資料
urls.py

urlpatterns = [
  path("<int:resume_id>",file,name="file")
]

views.py 檔,這邊避免亂數造成網頁壞掉,可以用get_object_or_404做個預防機制

def file(request,resume_id):
  resume = get_object_or_404(Resume,id=resume_id)
    return render(request,"file.html",{"resume":resume})

建立file.html,用{{}}印出資料,再放到對應的 html 標籤裡

<h1>履歷No.{{ reseme.id }}</h1>
{{ resume.title }} {{ resume.skill }} {{ resume.content }}

4.將 list 加入超連結,可以直連到頁面

<a href="{% url 'resumes:file' resume.id %}">
  <li>{{ resume.title }}</li>
</a>

Update 更新

在顯示已輸入資料的頁面中,增加更新的按鈕,並且連的一個新的頁面做更新。 1.在file.html檔中(顯示資料的頁面),幫按鈕家超連結,引導至更新的頁面

<footer>
  <a href="{% url 'resumes:edit' resume.id %}"><button>編輯履歷</button></a>
</footer>

2.在urls.py中建立路徑 path

 path("<int:resume_id>/edit",edit,name="edit")

3.在views.py中設定執行內容,基本上和file一樣。

def edit(request,resume_id):
    resume = get_object_or_404(Resume,id=resume_id)

    return render(request,"edit.html",{"resume":resume})

4.再來建立edit.html,資料送回file,用value="{{ resume.title }}帶入之前填的資訊
textarea的放在內容這邊

{% extends "shared/layout.html"%} {% block "content" %}
<h1>修改履歷</h1>

<form method="POST" action="{% url 'resumes:file' resume.id%}">
  {% csrf_token %}<br />
  title <br />
  <input type="text" name="title" value="{{ resume.title }}" /><br />
  content <br />
  <textarea name="content">{{ resume.content }}</textarea>
  ...
  <button>更新</button>
</form>

{% endblock %}

5.最後views.py裡面設定file接收回傳的資訊

def file(request,resume_id):
    resume = get_object_or_404(Resume,id=resume_id)

    if request.POST:
        resume.title = request.POST.get("title")
        resume.skill = request.POST.get("skill")
        resume.content = request.POST.get("content")
        resume.save()

        return redirect("resumes:index")

    return render(request,"file.html",{"resume":resume})

Delete 刪除

1.在頁面加入刪除按鈕,並連結到刪除頁面 file

<footer>
  <a href="{% url 'resumes:edit' resume.id %}"><button>編輯履歷</button></a>
  <a href="{% url 'resumes:delet' resume.id %}"><button>刪除履歷</button></a>
</footer>

2.到urls.py設定路徑

 path("<int:resume_id>/delet",delet,name="delet")

3.到views.py設定執行delet

def delet(request,resume_id):
    resume = get_object_or_404(Resume,id=resume_id)
    return render(request,"delet.html",{"resume":resume})

4.建立刪除頁面delet.html 注意POST 只能用表單執行,所以這邊的刪除需要用表單包起來。回傳到自己可以不用寫路徑action=""

<h1>確認刪除履歷No.{{ resume.id }}</h1>
<footer>
  <a href="{% url 'resumes:file' resume.id %}"><button>取消刪除</button></a>

  <form method="POST" action="">
    {% csrf_token %}
    <br />
    <button>確認刪除</button>
  </form>
</footer>

5.在views.py設定delet接收到POST之後要做的事

def delet(request,resume_id):
    resume = get_object_or_404(Resume,id=resume_id)

    if request.POST:
        resume.delete()
        return redirect("resumes:index")

    return render(request,"delet.html",{"resume":resume})

終於完成了基本的 CRUD!!!!!
👏👏👏👏👏👏
接下來要挑戰在 30 分鐘內完上面的步驟囉 😱

增加 app

上面完成了一個 app 的設定,接下來進階一點,再加一個 app 進來

1.建立新的 app file

python manage.py startapp file_name

2.到setting.py裡面登記 app

3.設定 model.py

class Commenr(models.Model):
  content = models.TextFiels()
  created_at = models.DateTimeField(auto_now_add=True)

要連到外面,要使用ForeignKey外部鍵,兩個或多個資料表之間的關聯性,簡稱FK

class Commenr(models.Model):
  resume = model.ForeignKey(Resume, on_delete=models.CASCADE)

指連結到 Resume,
on_delete=代表當上層被刪除時,下層如何反應,有三種選項:

  • models.CASCADE:依層級,上層被刪,下層跟著刪
  • models.RESTRICT:因為下層有資料,所以上層不能被刪除(適合用在訂單上)
  • models.SET_NULL:上層被刪時,下層被設為空值

4.model migrate
做完這個步驟就可以開始做 CRUD 了

5.Creat
5-1.
這邊comments的第一個頁面就是file.html的頁面,所以直接寫在裡面就好。

<section>
  <form method="POST" action="{% url 'resumes:comments' resume.id %}">
    {% csrf_token %} <br />
    <textarea name="com_content" id=""></textarea>
    <button>新增留言</button>
  </form>
</section>

5-2.
接著設定路徑,按照設計,會顯示在 resume/id/comments。
resumes.urls.py

path("<int:id>/comments",執行,name="comments")

5-3.
再來到comments/views.py設定執行內容

@require_POST
def Com_index(request, id):
   #抓出resume
    resume = get_object_or_404(Resume, id=id)
   #新增comment
    comment = Comment()
    comment.content = request.POST.get("com_content")
    comment.resume_id = resume.id
    comment.save()

    messages.success(request,"留言已新增")
  #回去的頁面
    return redirect ("resumes:file", resume_id = resume.id)

@require_POST裝飾器,用途為“只接受 POST” 這樣留言送出之後,網站會抓到資料並回到file.html的頁面。

6.Read
6-1.
將留言顯示在file頁面,先到file把資料撈出來,在resumes/views.py

def file(request,resume_id):
  #抓資料
  commemts = resume.comment_set.all()

  return render(request,"file.html",{"resume":resume, "comments":comments})

resume.comment_set.all()裡的comment_set是抓資料庫裡的資料 最後要在字典裡把"comments":comments加進去,等一下再html才可以連得到

優化:在資料從資料庫抓出來之前先做反向排序

comments = resume.comment_set.order_by("-creat_at").all()

6-2.
file.htmlfor in 把字典裡的資料印出來

<ul>
  {% for comment in comments %}
  <li>{{ comment.content|breaks }} {{ comment.created_at}}</li>
  {% endfor %}
</ul>

時間設定,在資料庫的裡面,時間一律都是格林威治+0,要改成當地時間的話,曲要在setting.py中調整

TIME_ZONE = "Asia/Taipei"

在 Django 中,有template tags語法可以使用,去調整 HTML,linebreaks用來替代<br>做換行

6-3.
comments/views.py裡抓資料的另一種寫法,由resume去找留言的資料

def Com_index(request, id):
   #抓出resume
    resume = get_object_or_404(Resume, id=id)
   #新增comment
    content = request.POST.get("com_content")
    comment = resume.comment_set.creat(content = content)
    comment.save()

7.Delete
7-1.
file.html增加刪除按鈕

<form method="POST" action="{url '' }"></form>
{% csrf_token %}
<button>刪除留言</button>

7-2.
comments/urls.py設定路徑 urlpatterns =[ path("int:com_id",Com_delete, name=“delete”) ]

7-3.
comments/views.py建立要執行的

© 2024 - 2025 Joanna's Blog

🌟 A Hugo theme named Dream

About Me

Hello I’m Joanna, this is my blog

我會在這邊分享我學習程式語言的心得與筆記