Django基礎二靜態檔案和ORM

Hans_Wang發表於2022-03-17

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.

image

臨時解決方法:

在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>

image

拿到資料:
# 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

相關文章