Django-靜態文件


Django - 靜態文件

before

django提供了兩種靜態文件:

  • static,這類靜態文件用於django項目所需要的靜態文件,如js、css、img等等這些靜態文件。
  • media,這類靜態文件就是用戶相關的靜態文件了,比如存放用戶上傳的圖像、音視頻文件等。

static

來看怎么引入的。

首先,項目結構:

D:\TMP\DEMO\
├─app01   # app,內部結構略
|  └─static
|      └─index.css
├─demo
|  └─settings.py
├─static
|  ├─jquery-2.2.3.min.js
|  ├─a.jpg
│  └─bootstrap
│      ├─css
       |  └─bootstrap.css
│      └─js
|	  └─bootstrap.js
└─templates
   ├─books.html
   └─form.html

然后在settings.py中配置相關路徑:

import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_URL = '/static/'  # 通過別名指向STATICFILES_DIRS目錄,當然,別名也可以修改
STATICFILES_DIRS = [  # 列表或者元組都行
    os.path.join(BASE_DIR, 'static'),
    os.path.join(BASE_DIR, 'app01', 'static')   # 你也可以配置多個靜態文件目錄,只需拼上路徑就好了
]

我們把靜態文件CSSJSimg等都可以存放在static目錄。當然,這里面可以有多個靜態文件目錄。但每個目錄必須存在,才能后續引用。

引入方式1:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/jquery-2.2.3.min.js">
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.js">
</head>
<body>
</body>
<script src="/static/bootstrap/js/bootstrap.js"></script>
</html>

但是,我不推薦上面這種寫死了的形式,如果靜態文件位置改變,那就所有的頁面都無法引用靜態文件了。

所以,推薦下面這種形式。通過settings中的static別名,我們如果更改了具體的靜態文件路徑,只需要在setttings中更改別名的路徑就可以了,相當靈活。
引入方式2:

<!DOCTYPE html>
<html lang="en">
<head>
    {% load static %}   <!-- 使用load聲明引用靜態文件 -->
	{% static 'a.jpg' as a_obj %}  <!-- 某個文件被多次使用可以賦值給變量 -->
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>看中醫,學醫術,盡在中醫智庫</title>
    <link rel="stylesheet" href="{% static 'index.css' %}">   <!-- 這個引入是app01下的static中的靜態文件 -->
    <link rel="stylesheet" href="{% static 'base.css' %}"> <!-- 使用static別名進行引用靜態文件 -->
    <link rel="stylesheet" href="{% static 'base.css' %}">
    <link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}">
</head>
<body>
<img src="{% static 'a.jpg' %}" alt="">
<img src="{{ a_obj }}"></img>
</body>
<script src="{% static 'jquery-2.2.3.min.js' %}"></script>
<script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
</html>

推薦使用方式2。

get_static_prefix

get_static_prefix用的較少,它是獲取settings中STATIC_URL指向的別名,在模板中渲染時是這樣的:

<!DOCTYPE html>
<html lang="en">
<head>
    {% load static %}   <!-- 必須load static -->
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.js' %}">
    <link rel="stylesheet" href="{% get_static_prefix %}bootstrap/css/bootstrap.js">
</head>
<body>
{% get_static_prefix %}   <!--渲染成: /static/ -->

</body>
<script src="{% static 'bootstrap/js/bootstrap.js' %}"></script>
<script src="{% get_static_prefix %}bootstrap/js/bootstrap.js"></script> 
</html>

get_static_prefix的用法如上示例所示,它跟static的區別是,get_static_prefix需要手動拼接路徑;而static是Django會自動拼接路徑,推薦使用static

media

media通常就是跟用戶打交道了,所以涉及到表中的兩個字段:

  • FileField

    :一個專門用於文件上傳的字段。它的常用屬性有:

    • FieldFile.name,上傳文件的文件名。
    • FieldFile.size,獲取文件大小。
    • FieldFile.path,只讀屬性,通過調用底層的 path() 方法,訪問文件的本地文件系統路徑,用的較少。
  • ImageField

    :繼承 FileField 的所有屬性和方法,但也驗證上傳的對象是有效的圖像。除了 FileField 的特殊屬性外, ImageField 也有兩個常用屬性:

    • ImageField.height_field,模型字段的名稱,每次保存模型實例時將自動填充圖像的高度。
    • ImageField.width_field,模型字段的名稱,每次保存模型實例時將自動填充圖像的寬度。

除此之外,我們還可以在settings.py中,配置兩個media參數:

  • MEDIA_ROOT:默認值為''(空字符串)。用於保存用戶上傳的文件的絕對路徑。另外,MEDIA_ROOT 和 STATIC_ROOT 必須有不同的值。
  • MEDIA_URL: 默認值為''(空字符串),如果設置為非空值,則必須以斜線結束。結合路由中的配置,可以對外提供訪問。

來看看簡單的用法,如果你的settings.py中,沒有配置MEDIA_ROOT和MEDIA_URL,即兩個參數默認為空字符串,然后models.py中的字段設置如下:

from django.db import models

class Asset(models.Model):
    user = models.CharField(max_length=32, verbose_name='用戶名')
    avatar = models.FileField(upload_to='avatars/', verbose_name='用戶頭像', default='avatars/default.png')
    def __str__(self):
        return self.user

那么,如果生成一條用戶記錄時,圖片會被django默認保存到項目根目錄下的avatars目錄下,如果avatars目錄不存在,會先創建。而Asset表的avatar字段存的數據長這樣avatars/20190701134630.jpg,很明顯存的是路徑而不是文件內容。

但一切都是默認的,肯定不符合我們的需求,我們需要自己定義這些用戶文件應該保存到項目的哪個目錄下,當然通常這些文件將會保存到對應的文件服務器中。
來看看怎么自定義吧。
首先先來看配置文件settings.py

# 上傳的文件將會保存到項目根目錄下的media目錄下
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')  
MEDIA_URL = "/media/"   # 必須反斜杠結尾。

然后models.py不變:

from django.db import models

class Asset(models.Model):
    user = models.CharField(max_length=32, verbose_name='用戶名')
    avatar = models.FileField(upload_to='avatars/', verbose_name='用戶頭像', default='avatars/default.png')
    def __str__(self):
        return self.user

另外,urls.py還要進行特殊的配置:

from django.contrib import admin
from django.urls import path, re_path
from django.views.static import serve
from django.conf import settings
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    # 關於media配置的固定寫法
    re_path('media/(?P<path>.*)$', serve, {"document_root": settings.MEDIA_ROOT})
]

經過這么一配置啊,我們瀏覽器就可以通過訪問mediaurl,訪問到項目根目錄下的靜態文件了,如http://127.0.0.1:8000/media/avatars/20190701134630.jpg
來通過一個示例進行演示,包括文件上傳、刪除、下載的示例。
settings.py

# ----------------- media ------------
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = "/media/"

urls.py

from django.contrib import admin
from django.urls import path, re_path
from django.views.static import serve
from django.conf import settings
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    # 關於media配置的固定寫法
    re_path('media/(?P<path>.*)$', serve, {"document_root": settings.MEDIA_ROOT}),
    path('add/', views.add, name='add'),
    path('user_list/', views.user_list, name='user_list'),
    re_path('del_user/(?P<pk>.*?)/', views.del_user, name='del_user'),
    re_path('download/(?P<pk>.*?)/', views.download, name='download'),
]

views.py

import os
from django.shortcuts import render, HttpResponse, redirect
from django.http import FileResponse
# 解決圖片名稱不能是中文的問題,導入這個家伙
from django.utils.encoding import escape_uri_path
from app01 import models



def add(request):
    """ 添加用戶信息 """
    if request.method == "GET":
        return render(request, 'add_user.html')
    user = request.POST.get('user')
    avatar = request.FILES.get('avatar')

    models.Asset.objects.create(user=user, avatar=avatar)
    return redirect('/user_list/')


def user_list(request):
    """ 用戶列表頁 """
    if request.method == "GET":
        users = models.Asset.objects.all()
        return render(request, 'user_list.html', {"users": users})


def del_user(request, pk):
    # 如果直接使用delete刪除記錄,那么表中的記錄是會被刪除,但是avatar對應的文件不會被刪除
    # models.Asset.objects.filter(pk=pk).delete()
    # 所以,想要連文件一塊刪除,則需要手動刪除
    obj = models.Asset.objects.filter(pk=pk).first()
    obj.avatar.delete(save=True)  # 刪除對應的文件
    obj.delete()  # 刪除表中記錄

    return redirect('/user_list/')


def download(request, pk):
    # 下面示例演示從django項目的本地下載圖片
    # 如果是文件存儲在遠程,則可以通過requests模塊獲取文件內容,在封裝到FileResponse中
    file_obj = models.Asset.objects.filter(pk=pk).first()
    file_path = file_obj.avatar.path
    # print(file_path)
    f = open(file_path, 'rb')
    response = FileResponse(f)
    response['Content-Type'] = 'application/octet-stream'
    response['Content-Disposition'] = 'attachment;filename="{}"'.format(escape_uri_path(file_path.rsplit(os.sep, 1)[-1]))
    # 這里不能關閉文件
    # f.close()
    return response

models.py

from django.db import models


class Asset(models.Model):
    user = models.CharField(max_length=32, verbose_name='用戶名')
    avatar = models.FileField(upload_to='avatars/', verbose_name='用戶頭像', default='avatars/')
    def __str__(self):
        return self.user

demo\templates\add_user.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h3>添加用戶信息</h3>
<form action="" method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <input type="text" name="user" value="zhangkai">
    <input type="file" name="avatar">
    <input type="submit" value="提交">
</form>
</body>
</html>

demo\templates\user_list.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-10">
        <h3>用戶列表頁</h3>
            <a href="/add/"><button>添加用戶</button></a>
            <table class="table table-hover table-striped">
                <thead>
                <tr>
                    <th>用戶名</th>
                    <th>圖片</th>
                    <th>大小(kb)</th>
                    <th>操作</th>
                </tr>
                </thead>
                <tbody>
                {% for row in users %}
                    <tr>
                        <td>{{ row.user }}</td>
                        <td>{{ row.avatar.name }}</td>
                        <td>{{ row.avatar.size }}</td>
                        <td>
                            <a href="{% url 'del_user' row.pk %}" class="btn btn-default">刪除</a>
                            <a href="{% url 'download' row.pk %}" class="btn btn-primary">下載</a>
                        </td>
                    </tr>
                {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
</body>
</html>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM