Django基礎二靜態檔案和ORM
目錄
1. 靜態檔案
寫好後不會自動動態改變的檔案資源,如CSS
,js
,圖片,第三方框架檔案等等都屬於靜態檔案。預設我們會把靜態檔案都放在static
目錄下。這個目錄在Django
中是需要自己手動建立。
直接建立到專案的根目錄下即可。
static:
|___css 存放css檔案
|___img 存放圖片檔案
|___js 存放javaScript檔案
把目錄建立後啟動Django
是無法訪問的,會報404,因為沒有對外暴露訪問介面,還需要在settings.py
裡面配置。
1.1 靜態檔案基本配置:
在專案同名目錄下的settings.py檔案
在下面會看到:
"""
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
"""
在STATIC_URL下面加一行:
"""
STATICFILES_DIRS = [
BASE_DIR / "static",
]
"""
即可。
而且裡面可以加多個,如下:
STATICFILES_DIRS = [
BASE_DIR / "static",
'/var/www/static/',
]
然後在HTML檔案裡配置css,js等配置檔案
<head>
<script src="/static/bootstrap-3.4.1-dist/js/jquery-3.6.0.min.js"></script>
<link href="/static/bootstrap-3.4.1-dist/css/bootstrap.min.css" rel="stylesheet">
<script src="/static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
</head>
1.2 靜態檔案進階配置
STATIC_URL = '/static/' # 介面字首
"""
有了這個介面字首,如果要訪問靜態檔案資源,必須要static開頭。
寫了這個介面字首之後,就擁有了訪問STATICFILES_DIRS裡面配置的目錄內資源的許可權。
STATICFILES_DIRS = [
BASE_DIR / "static",
'/var/www/static/',
]
訪問順序為自上而下查詢,找到後就返回
"""
STATIC_URL = '/static/'
在書寫的時候必須要以static
開頭,如果更改了html
裡面也需要修改,否則訪問不到。
<script src="/static/bootstrap-3.4.1-dist/js/jquery-3.6.0.min.js"></script>
<link href="/static/bootstrap-3.4.1-dist/css/bootstrap.min.css" rel="stylesheet">
<script src="/static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
這裡的static為介面字首。
如果這裡不想寫成固定的,或者讓它動態更新,這樣不管``STATIC_URL = '/xxx/' `寫成什麼都可以訪問到這些靜態檔案。
方法:
在HTML檔案裡:
增加:
{% load static %}
<script src="{% static 'xx/yy/zz.js'%}"></script>
示例:
{% load static %}
<script src="{% static 'bootstrap-3.4.1-dist/js/jquery-3.6.0.min.js'%}"></script>
<link href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}" rel="stylesheet">
<script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
<img src="{% static 'my_app/example.jpg' %}" alt="My image">
settings.py裡配置:
STATIC_URL = '/static/' # 這時這裡的static可以隨意改名了
STATICFILES_DIRS = [
BASE_DIR / "static",
]
2. request引數
在views.py
檔案裡寫的函式都要帶一個request
引數,這個具體是做什麼的?
先寫一個登入頁面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<p class="text-center">登入</p>
<div class="col-md-8 col-md-offset-2">
<form action="" method="post">
username:<input type="text" name="name" class="form-control">
password:<input type="password" name="pwd" class="form-control">
<input type="submit" value="提交" class="btn btn-success btn-block">
</form>
</div>
</div>
</div>
</body>
</html>
# <form action="" method=""> action不寫預設向自己這個頁面提交,method不寫得使用get方法提交。get方法提交就會把輸入的內容直接顯示在瀏覽器上。所以一般使用post方法提交。由於沒寫處理post的方法,所以這裡會報錯:
Forbidden (403)
CSRF verification failed. Request aborted.
臨時解決方法:
在settings.py裡面找到MIDDLEWARE,然後把csrf相關的註釋掉
MIDDLEWARE = [
#'django.middleware.csrf.CsrfViewMiddleware',
]
現在訪問這個頁面不管是get
請求還是post
請求,都向這個頁面提交,但是使用get
請求的時候,拿到這個頁面,使用post
請求返回:"OK,已提交"
# view.py檔案:
from django.shortcuts import render
def login(request):
print(request.method)
return render(request,'login.html')
列印後發現,
get請求會列印一個全大寫的:GET
post請求列印一個全大寫的:POST
所以可以根據這個來判斷請求的不同,返回的內容不同
程式碼如下:
from django.shortcuts import render,HttpResponse
# Create your views here.
def login(request):
if request.method == 'POST':
return HttpResponse("OK,已提交")
return render(request,'login.html')
如何拿到使用者提交過來的資料
# views.py
from django.shortcuts import render,HttpResponse
# Create your views here.
def login(request):
if request.method == 'POST':
# 獲取使用者提交的資料
print(request.POST)
username = request.POST.get('name')
password = request.POST.get('pwd')
print(username, password)
return HttpResponse("OK,已提交")
return render(request,'login.html')
上面的方法雖然可以拿到資料,但是有個小問題,就是多選的時候使用get方法只能拿到最後個。如果想要拿到全部,則要使用.getlist()
示例:
<html>
<form action="" method="post">
username:<input type="text" name="name" class="form-control">
password:<input type="password" name="pwd" class="form-control">
<input type="checkbox" name="hobby" value="read">read
<input type="checkbox" name="hobby" value="jump">jump
<input type="checkbox" name="hobby" value="speak">speak
<input type="submit" value="提交" class="btn btn-success btn-block">
</form>
</html>
拿到資料:
# views.py
from django.shortcuts import render,HttpResponse
# Create your views here.
def login(request):
if request.method == 'POST':
# 獲取使用者提交的資料
print(request.POST)
username = request.POST.get('name')
password = request.POST.get('pwd')
hobby = request.POST.get('hobby')
print(username, password, hobby)
return HttpResponse("OK,已提交")
return render(request,'login.html')
# 結果:
hello 123 speak
發現只拿到了speak這一個,前面的read和jump沒有拿到。如果要拿到就要使用.getlist()
# views.py
from django.shortcuts import render,HttpResponse
# Create your views here.
def login(request):
if request.method == 'POST':
# 獲取使用者提交的資料
print(request.POST)
username = request.POST.get('name')
password = request.POST.get('pwd')
hobby = request.POST.getlist('hobby')
print(username, password, hobby)
return HttpResponse("OK,已提交")
return render(request,'login.html')
# 執行後拿到的資料:
hello 123 ['read', 'jump', 'speak']
上傳檔案
上傳檔案需要一個前提:
form裡面必須有enctype引數
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="file">
</form>
views.py:
from django.shortcuts import render,HttpResponse
# Create your views here.
def login(request):
if request.method == 'POST':
#data = request.FILES.get('file')
data = request.FILES.getlist('file')
print(data)
目前request
方法:
request.method 獲取當前請求方法,並結果是一個純大寫的字串
request.POST 獲取使用者post請求過來的基本資料(不包含檔案)
get() 拿到最後一個元素
getlist() 拿到全部元素
request.GET 獲取使用者get請求過來的基本資料
get() 拿到最後一個元素
getlist() 拿到全部元素
3. Django配置資料庫
具體文件:
https://docs.djangoproject.com/en/3.2/ref/settings/#databases
配置:
在settings.py裡面找到DATABASES,把預設配置修改了:
# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': BASE_DIR / 'db.sqlite3',
# }
# }
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # MySQL的驅動程式
'NAME': 'firstDjango', # 資料庫名
'USER': 'root', # 資料庫登入使用者名稱
'PASSWORD': '123456', # 登入密碼
'HOST': '192.168.1.109', # 登入ip
'PORT': '3306', # 埠
}
}
配置完後啟動Django 專案發現會報錯:
django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module.
Django預設使用MySQLDB這個模組連線MySQL資料庫,現在我們使用pymysql模組,所以要使用PyMySQL模組替換掉MySQLDB,方法:
在專案目錄下的__init__.py 或 應用目錄裡面的__init__.py 檔案裡新增:
__init__.py檔案:
import pymysql
pymysql.install_as_MySQLdb()
就可以解決,然後啟動。
修改地方:
例如專案名是firstDjango,應用名是first
firstDjango
|- __init__.py
first
|- __init__.py
這兩個地方任意一個檔案裡修改都可以。
4. Django ORM
ORM:物件關係對映
類 ————> 表
物件 ————> 表裡面的資料
物件點屬性 ————> 欄位對應的值
優點是:不懂SQL語句也能運算元據庫
缺點: 封裝了SQL語句,執行速度比較慢。
4.1 建立表
在Django
裡運算元據庫要寫在應用的models.py
檔案裡。
使用Django在資料庫裡裡建立一個表:
第一步: 寫建立語句程式碼:
# models.py
"""
from django.db import models
# Create your models here.
class User(models.Model):
# 相當於id int primary key auto_increment
id = models.AutoField(primary_key=True)
# 相當於 name(varchar(32)) CharField必須有個max_length的引數
name = models.CharField(max_length=32)
# age int
age = models.IntegerField()
"""
第二步,資料庫遷移:
"""
資料庫遷移命令:
1. 將資料據先記錄到migrations目錄下。
python3 manage.py makemigrations
2. 真正執行資料庫遷移操作。
python3 manage.py migrate
*** 只要是動了models.py裡面和資料庫相關的程式碼就要執行一下上面的兩條命令
"""
如果不指定主鍵,ORM
則會主動建立一個id
的主鍵,如果不想讓主鍵欄位叫id
,自己可以手動指定。
4.2 增加欄位
# 增加欄位:
# 如增加一個password欄位。
class User(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32,verbose_name='使用者名稱')
password = models.CharField(max_length=32,verbose_name='密碼') #
age = models.IntegerField()
"""
verbose_name='xx' 增加一個註釋,可以寫中文
寫完後執行:
python3 manage.py makemigrations
python3 manage.py migrate
執行的時候會提示:
Provide a one-off default now (will be set on all existing rows with a null value for this column)
就是新加的欄位,是否能為空,或設定一個預設值,解決方法有兩種
"""
# 方法一,屬性為空:
password = models.CharField(max_length=32,verbose_name='密碼', null=True)
# 方法二,設定預設值
password = models.CharField(max_length=32,verbose_name='密碼',default='123456')
4.3 修改欄位:
# 原始碼:
"""
class User(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32,verbose_name='使用者名稱')
password = models.CharField(max_length=32,verbose_name='密碼') #
age = models.IntegerField()
"""
# 修改後:
"""
class User(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=64,verbose_name='使用者名稱')
password = models.CharField(max_length=32,verbose_name='密碼') #
age = models.IntegerField()
"""
然後執行:
python3 manage.py makemigrations
python3 manage.py migrate
4.4 刪除欄位
# 刪除欄位,直接把欄位在程式碼裡註釋即可:
"""
class User(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=64,verbose_name='使用者名稱')
password = models.CharField(max_length=32,verbose_name='密碼') #
#age = models.IntegerField()
"""
然後執行:
python3 manage.py makemigrations
python3 manage.py migrate
4.5 查詢資料
登入的時候從資料庫校驗,如果使用者名稱和密碼正確,提示登入成功。
應用目錄下:
# views.py
from django.shortcuts import render,HttpResponse
from first import models
# Create your views here.
def login(request):
if request.method == 'POST':
# 獲取使用者提交的資料
print(request.POST)
username = request.POST.get('name')
password = request.POST.get('pwd')
# select * from user where name='使用者輸入的登入名' and password='使用者輸入的密碼'
user_obj = models.User.objects.filter(name=username,password=password).first()
#上面返回了一個物件方法,物件在呼叫的時候會執行__str__函式,所以在models.py里加上這個函式
print(user_obj)
if user_obj:
return HttpResponse("登入成功")
return render(request,'login.html')
# models.py
from django.db import models
# Create your models here.
class User(models.Model):
# 相當於id int primary key auto_increment
id = models.AutoField(primary_key=True)
# 相當於 name(varchar(32)) CharField必須有個max_length的引數
name = models.CharField(max_length=32)
password = models.CharField(max_length=32)
# age int
age = models.IntegerField()
def __str__(self):
return self.name
4.6 插入資料
使用者註冊
第一:先準備註冊頁面
templates目錄下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<p class="text-center">註冊</p>
<div class="col-md-8 col-md-offset-2">
<form action="" method="post" enctype="multipart/form-data">
username:<input type="text" name="name" class="form-control">
password:<input type="password" name="pwd" class="form-control">
<input type="submit" value="提交" class="btn btn-warning btn-block">
</form>
</div>
</div>
</div>
</body>
</html>
第二,編寫使用者註冊程式碼
# 應用目錄下views.py
from django.shortcuts import render,HttpResponse
from first import models
def res(request):
if request.method == 'POST':
# 獲取使用者提交的資料
print(request.POST)
username = request.POST.get('name')
password = request.POST.get('pwd')
# 寫入資料庫
# 不考慮驗證使用者是否存在
models.User.objects.create(name=username, password=password)
return HttpResponse("註冊成功")
return render(request, 'res.html')
第三,路由和檢視函式對應
專案名目錄下:
# urls.py
from first import views as views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login),
path('res/', views.res),
]
第四,重啟Django專案
python manage.py runserver
4.7 檢視全部資料
要把使用者的資料全部展示到頁面:
一,準備展示頁:
#templates目錄下home.html:
<table class="table table-striped table-hover">
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>pwd</th>
</tr>
</thead>
<tbody>
{% for foo in userdata %}
<tr>
<td class="success">{{ foo.id }}</td>
<td class="warning">{{ foo.name }}</td>
<td class="danger">{{ foo.password }}</td>
</tr>
{% endfor %}
</tbody>
</table>
二,編寫獲取全部使用者資訊程式碼:
# 應用名目錄下views.py
from django.shortcuts import render,HttpResponse
from first import models
def home(request):
user_obj = models.User.objects.all()
# select * from user;
return render(request, 'home.html', {'userdata':user_obj})
三, 路由和檢視函式對應關係:
# 專案名下urls.py
from first import views as views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login),
path('res/', views.res),
path('home/', views.home),
]
四,重啟Django專案
python manage.py runserver
4.8 利用頁面編輯資料庫裡資料
一,準備展示頁:
<table class="table table-striped table-hover">
<thead>
<tr>
<th>編號</th>
<th>姓名</th>
<th>密碼</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for foo in userdata %}
<tr>
<td class="success">{{ foo.id }}</td>
<td class="warning">{{ foo.name }}</td>
<td class="danger">{{ foo.password }}</td>
<td colspan="info">
<a href="/edit?edit_id={{ foo.id }}">編輯</a>
<a href="/delete?delete_id={{ foo.id }}">刪除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
二,編寫獲取全部使用者資訊程式碼:
# 應用名目錄下views.py
def show(request):
user_obj = models.User.objects.all()
return render(request, 'show.html', {'userdata':user_obj})
def edit(request):
edit_id = request.GET.get('edit_id')
edit_obj = models.User.objects.filter(id=edit_id).first()
if request.method == 'POST':
username = request.POST.get('name')
password = request.POST.get('pwd')
# 修改資料方法一:
models.User.objects.filter(id=edit_id).update(name=username, password=password)
# 修改資料方法二:
# edit_obj.name=username
# edit_obj.password=password
# edit_obj.save()
return redirect('/show/')
return render(request, 'edit.html', {"edit_obj":edit_obj})
三, 路由和檢視函式對應關係:
# urls.py
from first import views as views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login),
path('res/', views.res),
path('home/', views.home),
path('show/', views.show),
path('edit/', views.edit),
]
四,重啟Django專案
python manage.py runserver
4.9 利用頁面刪除資料庫裡資料
一,準備展示頁:
同上頁面:
<a href="/delete?delete_id={{ foo.id }}">刪除</a>
二,編寫獲取全部使用者資訊程式碼:
# 應用名目錄下views.py
def delete(request):
delete_id = request.GET.get('delete_id')
models.User.objects.filter(id=delete_id).delete()
return redirect("/show")
三, 路由和檢視函式對應關係:
# 專案名下urls.py
from first import views as views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login),
path('res/', views.res),
path('home/', views.home),
path('show/', views.show),
path('edit/', views.edit),
path('delete/', lviews.delete),
]
四,重啟Django專案
python manage.py runserver
4.10 同步資料庫
如果資料庫已經有一些表了,如何通過Django ORM
操作?
如果已經建立了一個庫,並且裡面有一些表。現在Django要用到這個庫和裡面的表,如何利用Django操作已經存在的表。
一,使用inspectdb命令,它可以通過已存在的資料庫建立對應模型。
python3 manage.py inspectdb # 後面什麼都不寫,則把庫中全部表的對應模型都輸出。
python3 manage.py inspectdb 表名 # 只輸出某一個表
python3 manage.py inspectdb first_user
"""
class FirstUser(models.Model):
name = models.CharField(max_length=32)
password = models.CharField(max_length=32)
class Meta:
managed = False
db_table = 'first_user'
把上面的程式碼儲存到models.py裡面
"""
二,執行這兩個命令:
python3 manage.py makemigrations
python3 manage.py migrate #會初始化建立一些Django用到的表。
4.11 ORM建立外來鍵
# ORM 針對外來鍵欄位的建立位置
"""
一對多: 推薦建在多的一方
多對多:建在哪一方都可以,但推薦建在查詢頻率較高的表中
一對一: 建在哪一方都可以,但推薦建在查詢頻率較高的表中
"""
# 應用名目錄下models.py
from django.db import models
# Create your models here.
class User(models.Model):
id = models.IntegerField(blank=True, primary_key=True)
name = models.CharField(max_length=255, blank=True, null=True)
age = models.IntegerField(blank=True, null=True)
class Meta:
managed = True
db_table = 'user'
# 建立書籍表
class Book(models.Model):
title = models.CharField(max_length=32)
# 共8位,小數佔2位
price = models.DecimalField(max_digits=8, decimal_places=2)
# 出版社外來鍵(Django會在外來鍵欄位後面自動加_id字尾)
publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)
# 作者外來鍵
authors=models.ManyToManyField(to='Author')
# 出版社表
class Publish(models.Model):
title = models.CharField(max_length=32)
email = models.EmailField()
# 作者表
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField
#作者詳細表外來鍵(在外來鍵欄位後面自動加_id字尾)
author_detail = models.OneToOneField(to='AuthorDetail',models.CASCADE)
# 作者詳細表
class AuthorDetail(models.Model):
phone = models.BigIntegerField()
addr = models.CharField(max_length=128)
//ForeignKey和OneToOneField使用的時候必須要傳兩個引數:
to和on_delete,to就是上面寫的哪個表建立外來鍵。
on_delete為:
CASCADE 級聯刪除
PROTECT
RESTRICT (New in Django 3.1.)
SET_NULL
SET_DEFAULT
SET() 將 ForeignKey 設定為傳遞給 SET() 的值,如果傳遞了一個可呼叫的值,則為呼叫它的結果。
DO_NOTHING 不採取任何行動
具體見:https://docs.djangoproject.com/zh-hans/3.2/ref/models/fields/#django.db.models.ForeignKey.on_delete