詳解Django自定義圖片和文件上傳路徑(upload_to)的2種方式
最近在做一個(gè)仿知乎網(wǎng)站的項(xiàng)目了,里面涉及很多圖片和文件上傳。趁此機(jī)會(huì)我給大家總結(jié)下Django自定義圖片和文件上傳路徑的2種方式吧。
方法1: 在Django模型中定義upload_to選項(xiàng)。
Django模型中的ImageField和FileField的upload_to選項(xiàng)是必填項(xiàng),其存儲(chǔ)路徑是相對(duì)于MEIDA_ROOT而來的。
我們來看一個(gè)簡(jiǎn)單案例(如下所示)。如果你的MEDIA_ROOT是/media/文件夾,而你的上傳文件夾upload_to=“avatar", 那么你上傳的文件會(huì)自動(dòng)存儲(chǔ)到/media/avatar/文件夾。
class UserProfile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile') avatar = models.ImageField(upload_to='avatar', verbose_name="頭像")
如果你的文件名是sky.jpg, 那么圖片上傳后數(shù)據(jù)庫(kù)中的avatar字段為avatar/sky.jpg, 該字段指向圖片對(duì)象,而非絕對(duì)路徑。要在模板中使用該圖片,應(yīng)該使用avatar.url (即/media/avatar/sky.jpg)。
但在實(shí)際應(yīng)用中,請(qǐng)千萬別這么做。這里有2個(gè)嚴(yán)重問題。
- 所有用戶都把頭像上傳到了同一個(gè)avatar文件夾了
- 原文件名是什么,那么新文件名就是什么
試想用戶很多,很可能發(fā)生文件重名問題,造成后來用戶上傳的文件把前面用戶上傳的頭像覆蓋了,造成了用戶A掛用戶B頭像的狀況。
正確的做法是動(dòng)態(tài)定義上傳路徑,把圖片存儲(chǔ)到用戶自己的文件夾下,并對(duì)其重命名。如下圖所示。這樣圖片就會(huì)保存在/media/1/avatar/里了,而且文件以u(píng)uid命名。
from django.db import models from django.contrib.auth.models import User import uuid # Create your models here. def user_directory_path(instance, filename): ext = filename.split('.')[-1] filename = '{}.{}'.format(uuid.uuid4().hex[:8], ext) # return the whole path to the file return "{0}/{1}/{2}".format(instance.user.id, "avatar", filename) class UserProfile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile') avatar = models.ImageField(upload_to=user_directory_path, verbose_name="頭像")
上述案例顯然還有一個(gè)問題,不同系統(tǒng)路徑分隔符/和\是不一樣的,為保證代碼在不同系統(tǒng)中能重用,更好的方式是使用python的os模塊來拼接路徑。如下圖所示。
from django.db import models from django.contrib.auth.models import User import uuid import os # Create your models here. def user_directory_path(instance, filename): ext = filename.split('.')[-1] filename = '{}.{}'.format(uuid.uuid4().hex[:10], ext) # return the whole path to the file return os.path.join(instance.user.id, "avatar", filename) class UserProfile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile') avatar = models.ImageField(upload_to=user_directory_path, verbose_name="頭像")
用戶上傳文件可能是圖片,也可能是pdf文件,我們?nèi)绾伟阉鼈兎旁谕挥脩舻牟煌募A下呢?實(shí)現(xiàn)這個(gè)很簡(jiǎn)單,如下圖所示。
def user_directory_path(instance, filename): ext = filename.split('.')[-1] filename = '{}.{}'.format(uuid.uuid4().hex[:8], ext) sub_folder = 'file' if ext.lower() in ["jpg", "png", "gif"]: sub_folder = "avatar" if ext.lower() in ["pdf", "docx"]: sub_folder = "document" return os.path.join(instance.user.id, sub_folder, filename)
方法2: 在視圖中自定義上傳圖片或文件路徑
方法1最簡(jiǎn)單直白,但有一個(gè)較大缺陷,文件上傳后未經(jīng)處理就直接存儲(chǔ)了。假如用戶上傳了圖片,我們希望先對(duì)其壓縮或裁剪,然后再存儲(chǔ),或者我們不希望上傳圖片或文件到默認(rèn)的路徑,這時(shí)我們就有必要在視圖中自定義圖片或文件路徑了。例子如下。
@login_required def ajax_avatar_upload(request): user = request.user user_profile = get_object_or_404(UserProfile, user=user) if request.method == "POST": form = AvatarUploadForm(request.POST, request.FILES) if form.is_valid(): img = request.FILES['avatar_file'] # 獲取上傳圖片 cropped_avatar = crop_image(img, user.id) user_profile.avatar = cropped_avatar # 將圖片路徑修改到當(dāng)前會(huì)員數(shù)據(jù)庫(kù) user_profile.save() return HttpResponseRedirect(reverse('myaccount:profile')) def crop_image(file, uid): # 隨機(jī)生成新的圖片名,自定義路徑。 ext = file.name.split('.')[-1] file_name = '{}.{}'.format(uuid.uuid4().hex[:10], ext) cropped_avatar = os.path.join(uid, "avatar", file_name) # 相對(duì)根目錄路徑 file_path = os.path.join("media", uid, "avatar", file_name) # 裁剪圖片,壓縮尺寸為200*200。 img = Image.open(file) crop_im = img.crop((50,50,300, 300)).resize((200, 200), Image.ANTIALIAS) crop_im.save(file_path) return cropped_avatar
到此這篇關(guān)于詳解Django自定義圖片和文件上傳路徑(upload_to)的2種方式的文章就介紹到這了,更多相關(guān)Django 上傳路徑內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Django 如何實(shí)現(xiàn)文件上傳下載
- Django和Ueditor自定義存儲(chǔ)上傳文件的文件名
- 基于django和dropzone.js實(shí)現(xiàn)上傳文件
- python中Django文件上傳方法詳解
- Django后端分離 使用element-ui文件上傳方式
- Django Admin 上傳文件到七牛云的示例代碼
- Django實(shí)現(xiàn)任意文件上傳(最簡(jiǎn)單的方法)
- Django 解決上傳文件時(shí),request.FILES為空的問題
- Django中文件上傳和文件訪問微項(xiàng)目的方法
- django 文件上傳功能的相關(guān)實(shí)例代碼(簡(jiǎn)單易懂)
- django上傳文件的三種方式
相關(guān)文章
零基礎(chǔ)學(xué)習(xí)python偏函數(shù)語法的推導(dǎo)方法步驟
這篇文章主要介紹了零基礎(chǔ)學(xué)習(xí)python偏函數(shù)語法的推導(dǎo)方法步驟詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06Python圖像濾波處理操作示例【基于ImageFilter類】
這篇文章主要介紹了Python圖像濾波處理操作,結(jié)合實(shí)例形式分析了Python基于ImageFilter類實(shí)現(xiàn)的濾波處理相關(guān)操作技巧,需要的朋友可以參考下2019-01-01pandas取dataframe特定行列的實(shí)現(xiàn)方法
大家在使用Python進(jìn)行數(shù)據(jù)分析時(shí),經(jīng)常要使用到的一個(gè)數(shù)據(jù)結(jié)構(gòu)就是pandas的DataFrame,本文介紹了pandas取dataframe特定行列的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05Python中不同進(jìn)制的語法及轉(zhuǎn)換方法分析
這篇文章主要介紹了Python中不同進(jìn)制的語法及轉(zhuǎn)換方法,結(jié)合實(shí)例形式分析了Python不同進(jìn)制的表示方法及相互轉(zhuǎn)換方法,需要的朋友可以參考下2016-07-07Python如何統(tǒng)計(jì)函數(shù)調(diào)用的耗時(shí)
這篇文章主要為大家詳細(xì)介紹了如何使用Python實(shí)現(xiàn)統(tǒng)計(jì)函數(shù)調(diào)用的耗時(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-04-04Python中實(shí)現(xiàn)ipaddress網(wǎng)絡(luò)地址的處理
ipaddress庫(kù)提供了處理IPv4與IPv6網(wǎng)絡(luò)地址的類。這些類支持驗(yàn)證,查找網(wǎng)絡(luò)上的地址和主機(jī),以及其他常見的操作,本文就來介紹一下這些方法的使用,感興趣的一起來了解一下2021-06-06