chen sam
  • NEW!
    NEW!  Connect Ideas Across Notes
    Save time and share insights. With Paragraph Citation, you can quote others’ work with source info built in. If someone cites your note, you’ll see a card showing where it’s used—bringing notes closer together.
    Got it
      • Create new note
      • Create a note from template
        • Sharing URL Link copied
        • /edit
        • View mode
          • Edit mode
          • View mode
          • Book mode
          • Slide mode
          Edit mode View mode Book mode Slide mode
        • Customize slides
        • Note Permission
        • Read
          • Only me
          • Signed-in users
          • Everyone
          Only me Signed-in users Everyone
        • Write
          • Only me
          • Signed-in users
          • Everyone
          Only me Signed-in users Everyone
        • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invite by email
        Invitee

        This note has no invitees

      • Publish Note

        Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

        Your note will be visible on your profile and discoverable by anyone.
        Your note is now live.
        This note is visible on your profile and discoverable online.
        Everyone on the web can find and read all notes of this public team.

        Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

        Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

        Explore these features while you wait
        Complete general settings
        Bookmark and like published notes
        Write a few more notes
        Complete general settings
        Write a few more notes
        See published notes
        Unpublish note
        Please check the box to agree to the Community Guidelines.
        View profile
      • Commenting
        Permission
        Disabled Forbidden Owners Signed-in users Everyone
      • Enable
      • Permission
        • Forbidden
        • Owners
        • Signed-in users
        • Everyone
      • Suggest edit
        Permission
        Disabled Forbidden Owners Signed-in users Everyone
      • Enable
      • Permission
        • Forbidden
        • Owners
        • Signed-in users
      • Emoji Reply
      • Enable
      • Versions and GitHub Sync
      • Note settings
      • Note Insights New
      • Engagement control
      • Make a copy
      • Transfer ownership
      • Delete this note
      • Save as template
      • Insert from template
      • Import from
        • Dropbox
        • Google Drive
        • Gist
        • Clipboard
      • Export to
        • Dropbox
        • Google Drive
        • Gist
      • Download
        • Markdown
        • HTML
        • Raw HTML
    Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
    Create Create new note Create a note from template
    Menu
    Options
    Engagement control Make a copy Transfer ownership Delete this note
    Import from
    Dropbox Google Drive Gist Clipboard
    Export to
    Dropbox Google Drive Gist
    Download
    Markdown HTML Raw HTML
    Back
    Sharing URL Link copied
    /edit
    View mode
    • Edit mode
    • View mode
    • Book mode
    • Slide mode
    Edit mode View mode Book mode Slide mode
    Customize slides
    Note Permission
    Read
    Only me
    • Only me
    • Signed-in users
    • Everyone
    Only me Signed-in users Everyone
    Write
    Only me
    • Only me
    • Signed-in users
    • Everyone
    Only me Signed-in users Everyone
    Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Django學習記錄 太久沒有碰網頁後端框架了,真的忘的很快,記錄一下各項配製方法。 而且網路上很多Django的教學為舊版本,希望這篇教學可以幫助到有需要的人們!! 這篇僅是Django最基礎的操作以及運作原理,幫助大家快速上手這個好用的後端框架。 ## 0. Why Django? Django和PHP的差別? Django是一個以Python構建的後端大型框架,可以用各種Python的Package做一些進階功能,而且Python處理字串的能力遠比PHP強的多。 Django是一種MTV的框架: ![MTV框架圖](https://miro.medium.com/v2/resize:fit:992/format:webp/0*7C7POqWkWX4ThOBK.png) 整個框架由Model(資料庫), template(html), View(前端畫面)構成。不同於PHP一個檔案對應到一個網頁(後端),Django則是view.py內的一個function對應到一個網頁,多個function組成一個app,所有app有組成一個Project。 Django的另一特點就是所有的路徑都由後端設定,而不仰仗于檔案實際的位置,因此就算某些檔案路徑不同了也不會影響到網頁。 ## 1. 關於Django的Project和App ### Project 一個Project共用網路層面的設定,也就server的主要設定,例如資料庫、網頁Request、或是Url導向。 建立Django project指令如下: ```bash! django-admin startproject project_name ``` 會產生以下的檔案: ``` project_name ├── manage.py //指令集 └── project_name ├── settings.py //主要設定 ├── urls.py // 網址路徑設定 ├── wsgi.py //web request 設定 ├── asgi.py //asynchronize request 設定 ``` 看不懂檔案的用途沒關係,僅有settings.py比較常用到而已。 wsgi.py用來設定要連到哪一個server(通常是Nginx)。 Project建好使用runserver指令: ```bash! python manage.py runserver ``` localhost:8000 如果有以下畫面就是成功了!! ![截圖 2024-02-05 下午5.29.34](https://hackmd.io/_uploads/H1r9qXA56.png) 備註: 這個runserver只是跑一個暫時性的python server, 方便debug而已。其效能跟安全性都非常差,要上架時還是會需要其他server幫助!! ### App 一個App就是多個功能比較相近的網頁,那究竟哪些網頁才算是功能相近?這沒有一定的規則,只要自己覺得好管理就可以了。 當然想要把所有網頁放在同一個App或是一個網頁一個App也是沒問題的啦~。 創建App的指令: ```bash! python manage.py startapp app_name ``` 記得要跟manage.py同一個路徑下執行。 整個專案資料夾會變成這樣: ``` project_name ├── manage.py //指令集 ├── project_name └── app_name ├── admin.py ├── apps.py ├── models.py ├── tests.py └── views.py ``` 最後記得把新創建的App加到settings.py的installed_app列表內: ```python! INSTALLED_APPS = [ "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", "app_name", #新創建的app ] ``` 1. admin.py 用來設定Django admin內要顯示的東西,也可以自定義一些csv匯入之類,詳細會在後面Django admin細講。 2. apps.py 幾乎不會動到的設定,可以定義app啟動時的一些function等等。 3. models.py 資料庫的table定義,後面資料庫操作會再細談。 4. tests.py 用來寫一些測試小腳本的檔案,可以用來測試資料庫又不影響到真正的資料,不過我也不會用QQ。 官方文檔: https://docs.djangoproject.com/en/5.0/intro/tutorial05/ 5. views.py 定義各個網頁要怎麼顯示,最重要的一個檔案!!。 可以發現一個App內會有共用的view, models。所以通常我會把常用到一樣table的網頁定義成一個App,或者常用到同一個function的頁面放在同一個App內。 ## 2. template和View。 ### 構建前端的第一步 先在App資料夾底下新增一個templates資料夾,把index.html檔案放進去: ``` app_name ├──templates ├──index.html ├── admin.py ├── apps.py ├── models.py ├── tests.py └── views.py ``` index.html如下: ``` <!doctype html> <html> <head> <title>This is the title of the webpage!</title> </head> <body> <p>This is an example paragraph. Anything in the <strong>body</strong> tag will appear on the page, just like this <strong>p</strong> tag and its contents.</p> </body> </html> ``` 配置好了template, 就要把這個畫面給選染到view上面啦~ view.py: ```python! from django.shortcuts import render #新加入的function def testPage(request): return render(request, "index.html") ``` 這樣就完成了view function跟template的對應,最後把function配置一個url。 urls.py: ```python! from django.contrib import admin from django.urls import path from app_name import views #記得要import app的view urlpatterns = [ path("admin/", admin.site.urls), path("home", views.testPage) #給剛剛寫好的function設定一個url ] ``` 這時候runserver後,瀏覽器網址輸入localhost:8000/home就可以看到剛剛寫的網頁啦! ![截圖 2024-02-09 中午12.38.14](https://hackmd.io/_uploads/B1aS27Qo6.png) 所有檔案要被瀏覽器存取,一定都要經過urls.py的分配,這種方法也加強了網頁的安全性。 如果urls內path放空字串,網頁就會被map到localhost:8000。 urls dispatch還有其他進階的用法,詳細看一下官方document: https://docs.djangoproject.com/en/5.0/topics/http/urls/ ### static files Django內的static files(JS, CSS, IMG)也是統一由框架管理,不再透過file system的相對路徑去存取。 在settings.py裡面找到以下設定: ```python! STATIC_URL = "static/" ``` 這段定義每個app內的static資料夾,可以作為static file存取的路徑。我們在App建立一個static 資料夾,裡面放我們要的css檔案(或是任何靜態文件): ``` app_name ├──templates ├──index.html ├── static ├──index.css ├── admin.py ├── apps.py ├── models.py ├── tests.py └── views.py ``` index.css: ```css p { color: rebeccapurple; } ``` 可以用網址localhost:8000/static/index.css確定是否能存取檔案,若可以則代表static配置正確。 ![截圖 截圖 2024-02-09 下午5.03.15](https://hackmd.io/_uploads/r16P9wXs6.png) 那html中如何引用呢? 首先要在html的最上面加上: {% load static %} 只要放在static資料夾內的檔案都能用{% static "path_to_file"%}去存取。 ```htmlembedded <link href='{% static "index.css" %}' rel="stylesheet"/> ``` ![截圖 2024-02-09 下午4.46.58](https://hackmd.io/_uploads/H1Iq8wXia.png) 可以看到我們的網頁已經有吃到CSS檔案啦~ img的src也是用同樣的方法去存取。 ### include template 如果有一些常用的html code可以獨立成一個html檔案,在需要的時候include就好。像是網站的許多頁面都會用相同的navbar和footer,我們可以分別為footer和navbar創建html檔案。 ``` app_name ├──templates ├──index.html ├──navbar.html ├──footer.html ├── static ├──index.css ├── admin.py ├── apps.py ├── models.py ├── tests.py └── views.py ``` 然後在需要的位置include就好: ```htmlembedded! {% include "navbar.html"%} <p>This is an example paragraph. Anything in the <strong>body</strong> tag will appear on the page, just like this <strong>p</strong> tag and its contents.</p> {% include "footer.html"%} ``` 但有些template不只一個App需要,需要跨App也能存取該怎麼辦呢?這時候我們就要定義global template dirctory。 在settings.py裡面找到template的設定,把global template dir放到DIRS選項的位置: ```python! TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [BASE_DIR / "templates"], #定義global templates的位置 "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", ], }, }, ] ``` BASE_DIR代表的是Project的位置。有趣的是Django setting內的所有路徑都可以直接用 **/** 符號連接,不需要用OS.path.join()。 APP_DIRS 如果改成False,django就不會再從App內找templates資料夾了,只有DIRS裡面的會被當成template檔案。 ***備註*** 我常常網頁會用到一大堆plugin,jquery、boostrap、jspanel....,每次都要複製一大堆link code很麻煩,我就會把這些引用的code做成一個template,每個網頁去include就好。 ### Global static file 剛剛有提到跨App要存取template要設定Global template,同理跨App要存取static也要設定global static dirs。直接在settings.py加入以下設定: ```python! STATICFILES_DIRS = [ BASE_DIR / "static_file", ] ``` 就可以把project file底下的static_file資料內的開放給所有App存取。 ### send data to template Django可以將要用的資料打包成一個dictionary傳給前端。只要在view function return render時把資料放在最後一個參數。 view.py: ```python! def testPage(request): i = [x for x in range(1,10)] #一個0~9的list data = { "data1":"資料1", "data2":"資料2", "list":i, } return render(request, "index.html", data) ``` 前端用{{變數}}: ```htmlembedded! <!doctype html> {% load static %} <html> <head> <title>This is the title of the webpage!</title> <link href='{% static "index.css" %}' rel="stylesheet" /> </head> <body> {{data2}} <p>This is an example paragraph. Anything in the <strong>body</strong> tag will appear on the page, just like this <strong>p</strong> tag and its contents.</p> {{list}} </body> </html> ``` ![截圖 2024-02-10 下午5.16.10](https://hackmd.io/_uploads/H1sbkaEop.png) 如果要取出list內特定index: ```htmlembedded! {{list.3}} ``` ### for tag 或是用for loop tag: ```htmlembedded! <!doctype html> {% load static %} <html> <head> <title>This is the title of the webpage!</title> <link href='{% static "index.css" %}' rel="stylesheet" /> </head> <body> {{data2}} <p>This is an example paragraph. Anything in the <strong>body</strong> tag will appear on the page, just like this <strong>p</strong> tag and its contents.</p> {% for item in list%} <p>{{item}}</p> {% endfor %} </body> </html> ``` ![截圖 2024-02-10 下午6.03.06](https://hackmd.io/_uploads/HJjecpVip.png) ### if tag 當然有for tag也有if else tag: ```htmlembedded! {% if ... %} {% else if ...%} {% else %} {% endif %} ``` 像是宿舍公共空間借用系統的空間選擇欄位,要依據目前選擇的空間改變selected: ![截圖 2024-02-20 晚上9.18.11](https://hackmd.io/_uploads/B10TL7fna.png) ```htmlembedded! <select class="wide" id="dropdown"> <option value="1" selected="">雨樹L棟會議室</option> <option value="10">雨樹藝文空間</option> </select> ``` 就是使用for tag以及 if tag完成的: ```htmlembedded= <select class="wide" id="dropdown"> {% for space in region_space %} <option value={{space.id}} {% if space.id == request.GET.space_id %} selected {% endif %}>{{space.space_name}}</option> {% endfor %} </select> ``` 要特別注意的是,對於Django前端的變數還是有資料型態的差別的,所以如果==兩端的資料型態不同,是需要資料型態轉換的! 基本上都和python語法差不多,只是最後都要加上一個end tag。 還有很多酷酷tag和filter,包括變數資料型態的轉換(stringformat)或是變數的運算(add),請參考官方文檔: https://docs.djangoproject.com/en/5.0/ref/templates/builtins 備註: MTV這種形式的好處就是前後端做到完全分離,前端code只會有變數跟一些必要的for loop。 ### 什麼?前端可以存取POST? 不只是POST, GET、session、cookie,這些跟request有關的都可以直接在template用變數存取。 不過要確定setting.py內的templates context_processors有沒有這個設定: ```python! "django.template.context_processors.request" ``` 這樣就可以在前端用request.POST.name存取POST的內容!!(session, get, cookie同理) ```htmlembedded! <p id="hidden_id" >{{request.GET.space_id}}</p> ``` ### url tag **補充**: 還有很重要的tag是url tag, 用法: {% url "site_name" %} 只要給頁面一個別名,就可以用這個tag自動生成去往這個頁面的url。 這東西好用在哪裡呢?以宿服借用系統的navbar為例,點擊navbar上的標題就可以回到主頁。 但是如果用相對路徑,有一些頁面可能../就可以回到主頁,有一些要../../兩次才可以或是更多,如果用絕對路徑domain更改時又要改code,所以我們可以直接給主頁一個url name,在urls.py裡面: ```python! path("", views.home, name="home"), ``` 這樣我們就可以用{% url "home" %}回到主頁: ```htmlembedded= <nav class="navbar navbar-expand-lg navbar-dark bg-516464"> <div class="container px-5"> <a class="navbar-brand" href="{% url 'home'%}">中山大學宿舍公共空間借用系統</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav ms-auto mb-2 mb-lg-0"> <li class="nav-item"><a class="nav-link" href="https://housing-osa.nsysu.edu.tw/">宿服組網站</a></li> <li class="nav-item"><a class="nav-link" href="https://housing-osa.nsysu.edu.tw/p/412-1092-18050.php?Lang=zh-tw">借用須知</a></li> </ul> </div> </div> </nav> ``` ## 3.資料庫 ### 資料庫設定 Django 原先預設是使用sqllite,不過我自己習慣使用MySQL。 在 settings.py內找到DATABASES的設定,並改成: ```python! DATABASES = { "default": { "ENGINE": "django.db.backends.mysql", "NAME": "databaseName", "USER": "databaseUser", "PASSWORD": "databasePassword", "HOST": "localhost", "PORT": "portNumber", } } ``` 若沒有安裝pymysql package: ```bash! pip install pymysql ``` 最後記得要在project/__init__.py 或是 settings.py的最上面補上以下程式, 這段程式的目的是讓python可以直接透過pymysql package去連結資料庫: ```python! import pymysql pymysql.install_as_MySQLdb() ``` Django不管你連接什麼資料庫,都會轉為ORM,簡單來說就是一個table就會是一個Python class,table內的column就是class的attribute,這些class定義在app的models.py裡面。 **ps:** ***model就沒分local model或是global model了,如果要用到別的app的model, 直接from app import model就好了。*** ```python= class Space(models.Model): id = models.AutoField(primary_key=True) # Field name made lowercase. space_name = models.CharField(max_length=255) # Field name made lowercase. region = models.CharField(max_length=255) link = models.CharField(max_length=255, blank=True, null=True) eng_name = models.CharField(max_length=255) class Meta: managed = True #代表需要Django幫你在資料庫建立這個table db_table = 'Space' #資料庫內table的名字,預設會是django_space class Register(models.Model): signature = models.CharField(max_length=255, primary_key=True, null=False, blank=False) start_time = models.IntegerField() # Field name made lowercase. space = models.ForeignKey(Space, on_delete=models.CASCADE) # Field name made lowercase. The composite primary key (Space_id, Start_time, Date) found, that is not supported. The first column is selected. date = models.CharField(max_length=20) # Field name made lowercase. usable = models.IntegerField() user_id = models.CharField(max_length=255, blank=True, null=True) user_name = models.CharField(max_length=255, blank=True, null=True) user_phone = models.CharField(max_length=255, blank=True, null=True) user_dormnumber = models.IntegerField(blank=True, null=True) change_pwd = models.CharField(max_length=255, blank=True, null=True) class Meta: managed = True db_table = 'Register' unique_together = ('space', 'start_time', 'date') #這三個欄位合在一起必須唯一 class BlackList(models.Model): stu_id = models.CharField(primary_key=True, max_length=20) expire_time = models.DateField(blank=True, null=True) banned_reason = models.CharField(max_length=20, blank=True, null=True) class Meta: managed = True db_table = 'black_list' ``` 定義或是修改class後輸入指令: ```bash! python manage.py makemigrations python manage.py migrate ``` 這時就會看到我們的資料庫多了許多table: ![Screenshot from 2024-02-21 20-52-33](https://hackmd.io/_uploads/Bk9XfuXha.png) 除了Space, Register, black_list以外,其他都可以不用管,那些是django自己產生的一些紀錄。 ### 常見的資料庫欄位格式 資料欄位Options常用的有: <table> <tr> <th>選項</th> <th>意義</th> </tr> <tr> <td>null</td> <td>是否可以為null</td> </tr> <tr> <td>blank</td> <td>是否可以為空白字串</td> </tr> <tr> <td>primary_key</td> <td>是否為pk</td> </tr> <tr> <td>default</td> <td>欄位預設值</td> </tr> <tr> <td>choices</td> <td>限定欄位值只能填哪些, 很好用</td> </tr> <tr> <td>unique</td> <td>欄位值是否唯一</td> </tr> </table> 常用的資料型態則有: ```python= models.AutoField() #autoIncrement Integer models.CharField() #varchar models.IntegerField() #Integer models.DateField() #Date, 在python內可以當datetime.date物件處理 #偷偷抱怨一下,php要處理date真的超級麻煩,所以之前我都用varchar去存日期 models.DateTimeField() #Datetime, 時間加上日期,在python內可以當datetime.datetime物件處理 models.FileField() #Mysql沒有這種欄位,直接可以handle檔案的存取!超讚!! ``` **備註:** Django不支援multi-key primary key, 所以只能放一個autoincrement的pk, 然後再用unique_together ### 特殊的資料欄位 這些欄位是用來定義relational DB表格之間的關係,像是1對1資料、1對多資料... Django都會自動轉換成對應的表格,不需要自己從ER diagram轉成table。並且當資料違反原則時會自動報錯。 ```python= models.OneToOneField() #1對1關係 models.ForeignKey() #1對多關係 models.ManyToManyField() #多對多關係,資料庫會自動多建立一個表格 ``` 這些特殊欄位除了上面提到Option,還多了幾個: <table> <tr> <th>選項</th> <th>意義</th> </tr> <tr> <td>to</td> <td>有關係的table</td> </tr> <tr> <td>on_delete</td> <td>連結的資料消失時採去的動作</td> </tr> <tr> <td> parent_link</td> <td>繼承用的,不重要我也不會用QQ</td> </tr> </table> 詳細更多的Field還有Options請見官方文檔: https://docs.djangoproject.com/en/5.0/ref/models/fields/#django.db.models.FileField ### Query Django支援原本的SQL語法或是ORM對資料庫進行Query,個人建議簡單的操作像是SELECT, DELETE, INSERT用ORM,至於比較複雜的JOIN, GROUP_BY, 甚至是AGGREGATION就還是乖乖寫SQL吧!! #### SELECT ```python! #SELECT * from space where id = 1 AND space_name = "武嶺會議室"; space = Space.object.filter(id=1, space_name="武嶺會議室") #SELECT id, space_name from space where id = 1; space = Space.object.filter(id=1).values("id", "space_name") ``` 注意!!以上兩種function回傳不太一樣,前者是QuerySet(類似list的物件),裡面包著Space object;後者是QuerySet裡面包著dict。 例如: ```python! >>> Blog.objects.filter(name__startswith='Beatles').values('id', 'name', 'tagline') [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}] ``` 注意!!雖然QuerySet物件類似list, 操作也差不多,但在某些function只能接受list還是得要轉換。 **補充(不怎麼重要,可以跳過):** 如果使用values_list,則所有值會攤開成一個tuple: ```python! >>> Blog.objects.filter(name__startswith='Beatles').values_list('id', 'name') [(1, 'Beatles Blog')] ``` 如果再加上flat=TRUE就會攤開變成: ```python! >>> Blog.objects.filter(name__startswith='Beatles').values_list('id', 'name', flat=True) [1, 'Beatles Blog'] ``` **補充結束** #### INSERT INTO/UPDATE ```python! new_space = Space(id=2, space_name="武嶺交誼廳") new_space.save() #INSERT INTO Space (id, space_name) values (2, space_name); ``` 也可以用dic創建一個物件,在該物件有一大堆Fields時比較省力: ```python! record = { 'start_time' : request.POST.get('Start_time'), 'user_id' : request.POST.get('user_id'), 'user_dormnumber' : request.POST.get('user_dormnumber'), 'user_phone' : request.POST.get('user_phone'), 'change_pwd' : request.POST.get('change_pwd'), 'date' : request.POST.get('date'), 'user_name' : request.POST.get('name'), 'usable': 1 } new_record = Register(**record) new_record.save() ``` 如果要update,只要把物件Query出來修改後,用save()就可以了 #### DELET FROM ```python! space = Space.object.filter(id=1, space_name="武嶺會議室") space.delete() #DELET FROM Space where id=1; ``` ### 用SQL QUERY ```python! from django.db import connection with connection.cursor() as cursor: cursor.execute("YOUR SQL STATEMENT") result = cursor.fetchall() ``` **補充**: 以防有人不知道,python的with是一個專門把檔案、連線物件關住的東西,在離開with時會自動執行cursor.close(),避免連線資源未關閉。 更多進接或是常用操作可以看: https://www.twblogs.net/a/5b8793c82b71775d1cd7d91c ## 4. 其他網頁response 前面我們view function回傳都是render(),也就是一個網頁頁面。但有時候我們不希望回傳一整個頁面,像是是Ajax request就不需要回傳一個整個頁面,只要一個字串或是一些資料而已,這時候我們就會用HttpResponse(回傳一個字串)或是JsonResponse。 ### HttpResponse 例如登入管理者模式的Ajax: ```javascript! $.ajax({ url : "{% url 'private'%}", type: "post", data: {"pwd": pwd, "mode": "login"}, success: function(response) { alert(response); location.reload(); }, error: function(jqXHR, textStatus, errorThrown){ alert("AJAX error" + errorThrown); console.log('Error: ' + errorThrown); } }); ``` 這時private這個view function就會是這樣: ```python! def admin_mode(request): if request.method == "POST": if request.POST.get("mode") == "login": if request.POST.get("pwd") == "76211194": request.session['identity'] = "private" return HttpResponse("登入成功,切換為管理者模式") else: return HttpResponse("密碼錯誤!") else: request.session['identity'] = "normal" return HttpResponse("登出成功,切換為一般模式") else: raise Http404("Page not exit") ``` ### JsonResponse 通常用來回傳資料庫的內容給端。例如我們的預約介面是用Ajax取得預約資料的,view function就會長這樣: ```python= def get_regist(request): if request.method == "POST": space = request.POST.get('id') all_regist = Register.objects.filter(space=space).values("start_time", "space_id", "date", "user_id", "user_name", "user_phone", "user_dormnumber") all_regist = list(all_regist) if request.session['identity'] == "normal": for record in all_regist: record['user_id'] = record['user_id'][:-5] + "XXXXX" record['user_name'] = record['user_name'][0] + "X" + record['user_name'][2:] record['user_phone'] = "" return JsonResponse(all_regist, safe=False) else: raise Http404("Page not exit") ``` ## 5. 那些有點重要但我懶得打的內容 以下這些有可能會用到(和網站安全有關)但是較為繁瑣我懶得打,要麻煩各位自己找一下資料: 1. CSRF token --- Django避免跨站攻擊的機制 2. Django form --- 也是Django避免sql injection的一個東東 ## 6. Utility codes 這裡放一些常常用的function和code: ### cursor dicfetchall cursor.fetchall()回傳的會是一個tuple(tuple()),這樣會不利於取得資料欄位(只能用index很不方便),以下是讓cursor回傳tuple(dict())的code。 ```python= def dicfetchall(cursor): colums = [col[0] for col in cursor.description] return [ dict(zip(colums, row)) for row in cursor.fetchall() ] ```

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Google Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully