Django-開放靜態資源-獲取請求攜帶的資料-pychram連線資料庫-修改Django預設資料庫-DjangoORM操作--表管理-記錄管理-01
目錄
- 關於靜態資源訪問
- 為什麼要配置靜態檔案才能獲取靜態資源
- 常見的靜態檔案種類
- 如何配置來開啟訪問許可權
- 禁用瀏覽器快取
- django的自動重啟機制(熱啟動)
- 靜態檔案介面動態解析
- 向伺服器傳送資料
- 利用 form 表單預設的 get 請求攜帶
- form 表單改用 post 請求提交資料
- 回顧:action提交地址的三種寫法
- 程式碼區分請求方式
- 推薦寫法
- 獲取請求帶過來的資料
- request.POST
- 取資料
- request.GET
- 取資料
- request.POST
- pycharm 圖形化工具連線資料庫
- 準備工作,安裝外掛
- 配置連線資訊
- 圖形頁面基本操作
- 過濾多餘的字元編碼之類的?
- 不顯示資料表?
- 修改 django 專案配置(應用mysql)
- 在 settings.py 裡面配置資料庫連線資訊
- 指定資料庫“軟體”?
- django ORM
- 在models.py 裡創表模型類
- 建立表、修改表--資料庫遷移命令(同步到資料庫)
python3 manage.py makemigrations
記錄資料庫遷移python3 manage.py migrate
將資料庫修改記錄(migrations 中的記錄)真正同步到資料庫
- 簡便寫法
makemigrations
記錄資料庫遷移migrate
同步到資料庫- 注意
- 特殊點--表名會自動加上模組的字首
- 表字段的增刪改
- 增加表字段
- 刪除表字段
- 改欄位
- 資料的增刪改查(ORM)
- 查記錄
- 增加記錄
- 刪除記錄
- 更新記錄
- 使用者資訊增刪改查
- 程式碼書寫位置--個人小總結(待補充)
- app檔案下的
- 專案同名檔案下的
- app 和 專案同名目錄 都可以放的
- 專案根目錄的
django專案就類似於一所大學,各個app 就相當於二級學院
以登入功能為例走一個django專案(今日內容 引子)
關於靜態資源訪問
你可能會發現,在我們目前的 django 專案中的 html 模板中鏈入的 css 、js (這裡只伺服器本地的,CDN等除外)明明路徑是對的,請求得到的卻是 404 資源不存在
為什麼要配置靜態檔案才能獲取靜態資源
使用者可以訪問的資源,都在 url 中
只有 url 中開設(配置)相關的資源你才能訪問到(不然就可以根據路徑把網站原始碼都拿過去了)
後端資源一般都需要手動指定是否需要暴露給使用者
配置完之後也只有輸入完整的檔案路徑才能訪問到(也相對是一種保護措施)
對於前端已經寫好了的檔案,我們只是拿過來使用,那麼這些檔案都可以稱之為 “靜態檔案”
html檔案預設全部放在 templates 資料夾下(並且,如果是命令列建立的專案,並不會自帶 templates 資料夾,自己建立的就需要去配置檔案裡配置)
常見的靜態檔案種類
css
js
iamge (圖片)
bootstrap、fontawesome等前端框架,已經寫好了的
bootstrap-3.3.7-dist,bootstrap 是依賴於 jquery的,所以在導bootstrap 之前要先匯入 jquery
如何配置來開啟訪問許可權
預設的 django 專案 是沒有 static 這個檔案的,需要自己手動建立 static 資料夾,然後需要去 settings.py 檔案配置 static 靜態資源相關
# ... 差不多在 settings.py 檔案的最下面
STATIC_URL = '/static/' # 介面字首(跟請求路徑相關)
# 只要你想訪問靜態檔案中的資源,路徑就必須以 /static/ 開頭
# STATIC_URL = '/xxx/' # 引用靜態檔案資源的地方要改成 /xxx/....
# 下面這個是要手動配置的,手動將所有的靜態資原始檔暴露給使用者
STATICFILES_DIRS = [ # 跟實際檔案的查詢位置相關
# 這裡可以配置很多個,就類似於作業系統環境變數的查詢,依次去資料夾裡找
os.path.join(BASE_DIR, "static"), # 真正的資料夾路徑
]
建立完 static資料夾後,一般還會再在裡面手動建立三個資料夾
- css 放當前網站所有的 樣式 檔案(自己寫的)
- js 放當前網站所有的 js 檔案(自己寫的)
- image 放當前網站所有的 圖片 檔案
禁用瀏覽器快取
寫 django 專案最好禁用掉瀏覽器快取,不然可能寫的程式碼頁面上快取看不到效果、變化(資源載入地址等等)
要開著 F12開發者工具檢視 *****
django的自動重啟機制(熱啟動)
實時監測檔案程式碼變化,只要有變化,就會自動重啟,可能程式碼還沒有寫完就會自動報錯(如果有語法錯誤可能不會自動重啟,遇到邏輯錯誤就會重啟)
靜態檔案介面動態解析
如果你的產品經理要讓你上1000個靜態資源的字首改了,再改回來,總之就是改來改去,怎麼辦?
備註:這個一般是結合 static 靜態檔案配置來用的
使用靜態檔案介面動態解析
...html程式碼(這一塊一般在 head 標籤裡引用)
{% load static %} <-- 開啟靜態檔案介面動態解析 -->
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
...html程式碼
向伺服器傳送資料
利用 form 表單預設的 get 請求攜帶
form 表單提交方式預設是 get 請求,攜帶資料的方式是 url 問號後面跟資料(瀏覽器位址列直接拼接也是一樣的,本質都是傳送一個請求過去,資料都封裝成了請求的資料格式)
?username=jason&password=123
form 表單改用 post 請求提交資料
- 把html模版中 form 表單的 method 改成 post(method=‘post’)
- 去 settings.py 裡 把 CSRF 這個中介軟體禁用掉
回顧:action提交地址的三種寫法
- 不寫的情況下 預設往當前地址提交(url)
- 還可以寫字尾/index/ (django專案常用這種)
- 還可以寫全路徑
程式碼區分請求方式
request.method
能夠獲取前端請求方式(並且是全大寫的字串 POST、GET)
def test_request_way(request):
print(request.method, type(request.method))
# GET <class 'str'> # 直接瀏覽器敲 http://127.0.0.1:8000/test_request_way/ 的方繪製
return HttpResponse('alallala')
推薦寫法
可以根據這個來判斷請求方式,對於不同的請求方式作出不同的處理
def del_user(request):
if request. method == 'POST':
# post 請求的邏輯處理
return HttpResponse('這是一個 POST 請求!')
# get 請求的邏輯處理(如果是 post,上面就已經return 了,不會執行到這裡)
return HttpResponse('這是一個 GET 請求!')
獲取請求帶過來的資料
WSGI幫忙封裝了 request 等,也經過了 Django後端,才有了request 這個物件(請求相關內容 全在 environ 裡面)
GET、POST
request.POST
獲取前端表單 POST 提交的所有資料(就類似於一個大字典)
取資料
request.POST.get('username') # 雖然value是一一個列表但是預設只取列表最後一個元素
password = request.POST['password'] # --->強烈不建議你使用中括號的形式取值,不存在會直接報錯
# 如果想直接把列表全部拿出來 --> request.POST.getlist('hobby') # 獲取使用者愛好、下拉框的選項
request.GET
獲取前端 GET 提交的所有資料(就類似於一個大字典)
取資料
request.GET.get('username') # 雖然value是一一個列表但是預設只取列表最後一個元素
# 如果沒有 get 請求攜帶的資料,就是一個空字典
password = request.GET['password'] # --->強烈不建議你使用中括號的形式取值,不存在會直接報錯
# 如果想直接把列表全部拿出來 --> request.GET.getlist('hobby') # 獲取使用者愛好、下拉框的選項
pycharm 圖形化工具連線資料庫
準備工作,安裝外掛
然後安裝一下外掛( downloads...)
配置連線資訊
一定要注意選擇那個 MySQL for 5.1(mysql 版本不高的時候),就兩個選項反正不行換一個試試嘛
不然 Test Connection 可能會報錯
圖形頁面基本操作
不是重點,滑鼠懸浮上去都有提示,自己看吧。。。
過濾多餘的字元編碼之類的?
不顯示資料表?
修改 django 專案配置(應用mysql)
django 預設使用的是自帶的 sqlite 資料庫(一種小型的做測試用的資料庫)
要讓 django 專案應用其他資料庫(mysql),需要做如下兩步配置
在 settings.py 裡面配置資料庫連線資訊
配置的時候 key 必須全大寫
... 省略一堆 配置資訊
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 直接把原來的 sqlite3 改成 mysql
# mysql 相關配置資訊
'HOST': '127.0.0.1',
'PORT': 3306,
'USER': 'root',
'PASSWORD': '000000',
'NAME': 'day51', # 資料庫名
'CHARSET': 'utf8'
}
}
... 其他配置資訊
指定資料庫“軟體”?
在專案名下的 __init__.py
檔案或者是應用名檔案下的 __init__.py
檔案下加入一段程式碼(指定使用的資料庫軟體?)
django 預設用 MySQLdb 連資料庫的(需要自己引入,MySQLdb 比較老了,相容性也不太好,所以要自己指定)
import pymysql
pymysql.install_as_MySQLdb() # 把 pymysql 裝成 MySQLdb 或者 取別名成 MySQLdb ?
django ORM
跟之前 手擼ORM 核心思路一樣,只不過這個更加強大而已(強大不知道多少倍去了)
關係對映:
表 ---> 類
一條條記錄 ---> 物件
欄位對應的值 ---> 物件的屬性
在models.py 裡創表模型類
django 會預設給你的表建立一個名為 id 的主鍵欄位,所以可以不寫這個 id 主鍵
但如果不是名為 id (是 s_id) 那還是得自己寫,一旦你已經指定了主鍵欄位 那麼 django 就不會主動再給你建立了
注意點
- CharField 必須指定 max_length 引數,不指定會報錯
- 欄位修改的注意點(下面有展開介紹)
- 其他注意點 ...
app01/models.py
from django.db import models
# Create your models here.
class User(models.Model):
# 將id欄位設定為User表主鍵欄位 在django orm中 你可以不寫主鍵字典 django會預設給你的表建立一個名為id的主鍵欄位
# id = models.AutoField(primary_key=True) # 一旦你自己指定了主鍵欄位 那麼django就不會自動再幫你建立了
username = models.CharField(max_length=32) # username varchar(32) CharField必須要指定max_length引數
# password = models.IntegerField() # password int
password = models.CharField(max_length=64)
# addr = models.CharField(max_length=32,default='China') # default該欄位預設值
# age = models.IntegerField(null=True) # 該欄位允許為空
def __str__(self): # 重寫了物件的 __str__ 方法,這樣後面列印物件的時候就是這個字串了
return '我是user表中的物件:%s' % self.username
建立表、修改表--資料庫遷移命令(同步到資料庫)
python3 manage.py makemigrations
記錄資料庫遷移
僅僅是在 migrations 資料夾中 記錄資料庫的修改,並不會直接操作資料庫
在當前 app 的 migration 資料夾下會多出一個 .py 檔案(記錄資料庫更改)
python3 manage.py migrate
將資料庫修改記錄(migrations 中的記錄)真正同步到資料庫
要等一會兒(第一次執行資料庫遷移(還是同步啊?沒試)命令會自動建立一堆表(django需要依賴的表),後續就是更新多出來的這幾張表的記錄了)
簡便寫法
這裡寫會有提示,但還是要會自己完整寫, 萬一面試讓手寫呢?
makemigrations
記錄資料庫遷移
會產生類似如下的檔案
app01/migrations/0008_auto_20190916_2358.py
# -*- coding: utf-8 -*-
# Generated by Django 1.11.11 on 2019-09-16 23:58
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app01', '0007_remove_user_addr'),
]
operations = [
migrations.AlterField(
model_name='user',
name='password',
field=models.IntegerField(),
),
]
首次建立表時(寫模型類時)
app01/migrations/0001_initial.py
# -*- coding: utf-8 -*-
# Generated by Django 1.11.11 on 2019-09-16 04:29
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='User',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('username', models.CharField(max_length=32)),
('password', models.IntegerField()),
],
),
]
migrate
同步到資料庫
新增或者更新新出的那些 表的記錄
注意
只要動了models 中跟資料庫相關的程式碼,就必須重新執行上面的兩條命令,缺一不可
特殊點--表名會自動加上模組的字首
自動加字首,可以方便協同開發,解耦合,合在一起就行了(那大家都創 app01 呢?)
表字段的增刪改
改完後必須執行資料庫遷移的那兩條命令
而且一般也不會讓你去動表結構,表是在開發之前就要定下來的!
增加表字段
當表裡已經有記錄時,後續還要想新增欄位,需要指定預設值 或者 允許新增欄位為空
1.給新增的欄位設定預設值
addr = models.CharField(max_length=32,default='China') # default該欄位預設值
2.給新增的欄位設定成可以為空
age = models.IntegerField(null=True) # 該欄位允許為空
當沒有記錄 或者 表還未被建立時,則不會有上述問題
刪除表字段
- 直接在表模型類裡 加註釋 / 刪除
- 重新執行兩條命令即可
強調!:執行完之後,表中該欄位所對應的所有資料全部清空
---》 沒事兒別瞎註釋!或者刪除(這不僅僅是python程式碼,還牽連著資料庫)
並且一般也不會真正意義上的刪除(除非設計不合理)
改欄位
結合新增欄位和刪除欄位(小推測,未實踐)
資料的增刪改查(ORM)
匯入 models 裡面的表
查資料(跟前面手動封裝的一樣)
from app01 import models # ORM操作需要使用 models 類中的名字
查記錄
get(拿到一個物件,物件沒有會報錯,不推薦)
models.User.objects.get(username=username, 條件2)
filter(拿到列表,可以放多個引數(條件))
models.User.objects.filter(username=username, password=password, 條件3)
返回的是一個列表(QuerySet),裡面放的才是一個個的物件
當查詢條件不存在時,不會報錯,只會返回一個空列表
filter 括號內支援寫多個引數,並且引數之間是 and 關係
print(res.query)
可以列印查詢語句(只有 QuerySet 物件才可以直接檢視內部對應的 sql 語句) orm 暫時做個瞭解,後面有詳解QuerySet 物件你可以把它當成列表操作,索引也可以用索引取,但是不推薦這麼做( QuerySet 只支援整數索引,不支援負數) 還支援切片操作(也不支援負數,切出來的結果還是一個 QuerySet 物件)
QuerySet 封裝的方法(個別)
..... filter().first() 拿列表中的第一個物件
空列表不會報錯
不推薦你使用索引取值,一旦沒有任何資料,再索引取值會報錯,但是如果用 .first()
雖然內部也是按索引取值,但是沒有資料, 也不會報錯,返回的是None
models.User.objects.filter(username=username).first()
少了 .first() 會報這個錯
all (拿到所有的)
models.User.objects.all()
直接拿到 User 表模型類的所有資料,結果是列表套物件
增加記錄
新增物件的兩種方式
create 方法
models.User.objects.create(username=username, password=password)
create方法能夠新增資料並且有一個返回值
返回值就是新增的資料物件本身
例項化物件呼叫 .save()
...省略一堆程式碼
user_obj = models.User(username=username, password=password)
user_obj.save()
...省略一堆程式碼
刪除記錄
models.User.objects.filter(條件).delete()
html中利用 a 標籤的 href 把引數發過去(加一個刪除功能)
models.User.objects.filter(條件).delete()
更新記錄
無論是什麼請求,request.GET 都能拿到 url 裡攜帶的引數
總體思路
先傳過來id
獲取記錄 重定向到頁面讓使用者修改
獲取使用者提交過來的新資訊,更新資料,重定向到列表頁
.filter(條件).update(username=username, password=password) 批量更新
models.User.objects.filter(id=edit_id).update(username=username,password=password)
.filter 拿到的是一個列表,所以 .filter
的操作 都是批量操作(如果 .filter 結果列表中有多個數據,那麼會一次性全部修改,就類似於 for迴圈一個個修改)
直接 物件.改屬性 .save儲存
edit_obj.username = username
edit_obj.password = password
edit_obj.save()
不推薦!--> 會從頭到尾將所有的欄位修改一遍(遍歷身上的屬性),效率極低
使用者資訊增刪改查
先通過 orm 展示所有的資料到前端
all() 拿所有資料
模板語法 for 迴圈
新增新增按鈕,能夠實現使用者的新增操作
利用 a 標籤的 href 直接觸發後端的邏輯
新增編輯、刪除按鈕
編輯
刪除
利用 get 請求攜帶引數的特點,在url的後面跟上對應資料的id值
request.GET.get()
如果是編輯
重新渲染一個頁面,將編輯物件傳遞到前端,讓使用者修改
如果是刪除
直接利用 filter(條件).delete()
重定向定位不同的頁面
與ORM相關的程式碼實現
app01/views.py
from django.shortcuts import render, HttpResponse, redirect
from app01 import models
# Create your views here.
def login(request):
# 檢視函式針對不同的請求方式 應該有不同的處理邏輯
# if request.method == 'GET':
# print('收到了')
# print(request.method) # 能夠獲取前端請求方式 並且是全大寫的字串
# print(type(request.method))
# return render(request,'login.html')
# elif request.method == 'POST':
# # 獲取使用者輸入 做相應的邏輯判斷
# return HttpResponse("拿到了 老弟")
if request.method == 'POST':
print(request.POST) # 獲取前端post請求提交過來的資料 就把它當成一個大字典即可
# <QueryDict: {'username': ['jason', 'zekai'], 'password': ['123']}>
username = request.POST.get('username') # 預設取列表最後一個元素
# password = request.POST['password'] # 不推薦 使用
password = request.POST.get('password')
# hobby = request.POST.getlist('hobby')
# print(username,password,hobby)
# print(type(username),type(password),type(hobby))
# 利用orm從資料庫獲取資料 校驗
# 1.查詢資料
# 1.1 get()
# user_obj = models.User.objects.get(username=username) # select * from user where username='jason'
# """
# get方法 能夠直接拿到資料物件本身 但是 當查詢條件不存在的時候 會直接報錯 所有不推薦使用
# """
# print(user_obj)
# print(user_obj.username)
# print(user_obj.password)
# 1.2 filter()
# res = models.User.objects.filter(username=username,password=password)
"""
filter查詢出來的結果是一個"列表 列表內放的才是一個個的資料物件本身"
當查詢條件不存在的時候 不會報錯 只會返回一個空列表
filter括號內 支援寫多個引數 並且引數與引數之間是and的關係
"""
# print(res.query) # 只有querySet物件才可以直接點query檢視年內部對應的sql語句
# 1.filter拿到的結果就是一個querySet物件(你現在只需要知道filter拿到的結果就能夠點query檢視sql語句)
"""
SELECT `app01_user`.`id`, `app01_user`.`username`, `app01_user`.`password`
FROM `app01_user`
WHERE (`app01_user`.`username` = jason AND `app01_user`.`password` = 123)
"""
# print(res)
# user_obj = res[0:2]
"""
querySet物件 你可以吧它當做列表操作 取值也可以通過索引取(querySet只支援正數索引 不支援負數) 還支援切片操作(切出來的結果還是一個querySet物件)
但是不推薦你這麼做
"""
user_obj = models.User.objects.filter(username=username).first() # 拿列表中第一個資料物件
"""
不推薦你使用索引取值 原因在於一旦沒有任何資料 再索引取值會報錯
但是如果用first雖然內部也是按照索引取值 但是沒有資料 也不會報錯 返回的是None
"""
# print(user_obj,user_obj.username,user_obj.password)
if user_obj:
if user_obj.password == password:
return redirect('http://www.xiaohuar.com')
return HttpResponse('使用者不存在 ')
print(request.GET) # 如果沒有get請求攜帶的資料 就是一個空字典
print(request.GET.get('username'))
print(request.GET.getlist('hobby'))
return render(request, 'login.html')
"""
http://127.0.0.1:8000/static/bootstrap-3.3.7-dist/css/bootstrap.min.css
"""
def reg(request):
if request.method == 'POST':
username = request.POST.get("username")
password = request.POST.get('password')
# orm插入資料
# 1.create()
# res = models.User.objects.create(username=username,password=password) # insert into user(username,password) values(username,password)
# """
# create方法能夠新增資料 並且有一個返回值
# 返回值就是新增的資料物件本身
# """
# print(res)
# print(res.username)
# print(res.password)
# 2.利用物件
user_obj = models.User(username=username, password=password)
user_obj.save()
return render(request, 'reg.html')
def user_list(request):
# 將user表中的資料全部查出
data = models.User.objects.all() # select * from user
"""
拿到的也是一個querySet物件
"""
print(data.query)
return render(request, 'userlist.html', {'user_list': data})
def del_user(request):
# 根據使用者想要刪除的資料的id值 取資料庫中刪除資料
# 獲取到id值
delete_id = request.GET.get('id')
# 拿著id去資料庫中刪除
models.User.objects.filter(id=delete_id).delete() # delete from user where id = delete_id;
return redirect('/userlist/')
def update_user(request):
# 編輯 是基於已經存在了的資料 進行一個修改
# 邏輯:獲取使用者想要修改的資料的主鍵值 然後去資料庫修改資料
edit_id = request.GET.get('id')
# 給使用者將資料查出來 展示到頁面上 讓使用者自己修改
edit_obj = models.User.objects.filter(id=edit_id).first()
# 將編輯物件傳遞給前端頁面
if request.method == 'POST':
# 不要關係思維 post請求中也是獲取get請求攜帶的引數
username = request.POST.get('username')
password = request.POST.get('password')
# 更新資料
# 方式1:
# models.User.objects.filter(id=edit_id).update(username=username,password=password)
# update user set username = username,password = password where id = edit_id
"""
filter拿到是一個列表 filter操作其實都是批量操作
如果filter結果列表中有多個數據 那麼會一次性全部修改
類似於for迴圈一個個修改
"""
# 方式二(不推薦使用)
edit_obj.username = username
edit_obj.password = password
edit_obj.save()
"""
第二種方式會從頭到尾將所有的欄位全部修改一遍 效率極低
"""
return redirect('/userlist/')
return render(request, 'update_user.html', {"edit_obj": edit_obj})
def test_request_way(request):
print(request.method, type(request.method))
# GET <class 'str'>
return HttpResponse('alallala')
程式碼書寫位置--個人小總結(待補充)
--> 暨 django 目錄結構再解讀
為了防止後期搞混,不知道程式碼往哪寫,所以最好還是把,每個檔案寫在哪的搞清楚(app 裡面還是專案同名資料夾下?)
app檔案下的
views.py 檢視函式/類 一般都是分應用(某個方面)來對應功能(檢視函式)的
models.py 資料庫模型類,一般還會給模型類加上app的字首(django設計的是可以分開開發,最後合併,故這裡這樣做能保證資料表名不重複(那app名字一樣呢...))
專案同名檔案下的
urls.py 路由配置
settings.py django暴露給使用者可以配置的配置資訊,這裡包含了 app 註冊、templates 路徑配置、static 靜態資源路徑配置等
app 和 專案同名目錄 都可以放的
單獨拎出來可能記得更深點吧
__init__.py 前面指定資料庫軟體的
import pymysql
pymysql.install_as_MySQLdb()
專案根目錄的
static 靜態資原始檔夾,要記得改配置(settings.py、html引入的時候用static檔案路徑動態解析)
templates 模版資料夾,要記得配置(settings.py)
大多通過 manage.py 執行 django 的命令
--> 這個檔案專門用來讀取命令列命令,並作出處理