【4】Django上傳圖片后怎么使用圖片呀喂?

樓主之前做了一個(gè)IT新聞聚合的網(wǎng)站叫三四秒,這個(gè)網(wǎng)站是用爬蟲直接把數(shù)據(jù)抓取到數(shù)據(jù)庫,然后在前臺搭建個(gè)頁面展示出來,所以樓主我只要隔山差五檢查一下爬蟲是否正常運(yùn)作就行,這個(gè)項(xiàng)目沒有User用戶模塊、UGC模塊,也沒有Comment模塊,所以理所當(dāng)然地樓主從來沒有實(shí)踐過圖片怎么上傳和展示。

那今天樓主決定勇敢的跨出這一步。我們做一個(gè)注冊頁面,填寫一個(gè)用戶名、上傳一個(gè)圖片,點(diǎn)擊提交后跳轉(zhuǎn)到注冊成功頁面并把圖片上傳到我們服務(wù)器上,最后在注冊成功頁面把剛剛的用戶名和圖片顯示出來。

1、創(chuàng)建一個(gè)項(xiàng)目名字叫mysite(要不是因?yàn)閼械闷鹈?,怎么可能叫mysite這么沒有創(chuàng)意的名字呀喂)。

django-admin startproject mysite

2、進(jìn)入到mysite文件夾,創(chuàng)建一個(gè)app應(yīng)用叫my_reg(好吧,我承認(rèn)起名字是編程界最難的事了)。

cd mysite
django-admin startapp my_reg

3、立刻把my_reg這個(gè)app添加在settings.py中。

INSTALLED_APPS = (
    ...
    'my_reg',
)```

4、第一步當(dāng)然是創(chuàng)建數(shù)據(jù)了,也就是User模型,用來儲存用戶名和圖片……的路徑。

from django.db import models

這里的上傳路徑就是mysite/upload/xxx.jpg

class User(models.Model):
username = models.CharField(max_length=20)
headImg = models.FileField(upload_to='./upload/')```

5、創(chuàng)建完數(shù)據(jù)模型,要養(yǎng)成好習(xí)慣,就是同步一下數(shù)據(jù)庫。

python manage.py makemigratons
python manage.py migrate

6、然后我們就開始寫路由url了,添加兩個(gè)url,一個(gè)是注冊頁面,一個(gè)是注冊完成頁面??吹较旅孢@兩個(gè)放蕩不羈的名字,相信你應(yīng)該已經(jīng)知道哪個(gè)是哪個(gè)了吧。

urlpatterns = [
    ...
    url(r'^register/$', 'my_reg.views.reg_index', name='my_regi'),
    url(r'^register/done/$', 'my_reg.views.result', name='reg_done'),
] ```

7、既然我們在路由url里寫到了`views`里的幾個(gè)函數(shù),那么我們這就去完成它。

from django.shortcuts import render
from django.http import HttpResponseRedirect
from django import forms
from my_reg.models import User

創(chuàng)建一個(gè)form表單類

class UserForm(forms.Form):
username = forms.CharField()
headImg = forms.FileField()

第一次打開頁面不是POST請求,所以走else那條路,創(chuàng)建一個(gè)form表單,然后在前臺顯示。第二次點(diǎn)擊“提交”按鈕是POST請求,走if那條路:意思就是這個(gè)表單請求內(nèi)容有files文件,然后如果它們有數(shù)據(jù),就存到數(shù)據(jù)庫中,并且把用戶名放在session中,最后跳轉(zhuǎn)到一個(gè)新的url去。

def reg_index(request):
if request.method == 'POST':
uf = UserForm(request.POST, request.FILES)
if uf.is_valid():
uname = uf.cleaned_data['username']
hImg = uf.cleaned_data['headImg']
u = User()
u.username = uname
u.headImg = hImg
u.save()
request.session['user_info'] = uname
return HttpResponseRedirect('/register/done/')
else:
uf = UserForm()
return render(request, 'my_reg/reg.html', {'uf': uf})

從session中找到這個(gè)用戶名,按照用戶名找到數(shù)據(jù)庫中的用戶信息,把用戶信息展示出來。

def result(request):
uuu = User.objects.get(username=request.session['user_info'])
return render(request, 'my_reg/result.html', {'user': uuu})```

8、views里面用到了兩個(gè)html頁面,一個(gè)是注冊頁面,一個(gè)是注冊完成頁面,我們簡單搭建一下:

# 注冊頁面
...
    <h1>Register!</h1>

    <form method="post" enctype="multipart/form-data" action="{% url 'my_regi' %}">
        {% csrf_token %}
        {{ uf.as_p }}
        <input type="submit" value="OK"/>
    </form>
...```

注冊成功頁面

...
<p>Result!</p>
<p>{{user.username}}</p>
<p>name done!</p>
<img src="這里放的是圖片的路徑" alt=""/>
...```

9、好了,這個(gè)上傳圖片和展示圖片的程序就做好了。

有種別走啊

10、這個(gè)原理是:只要我們合理的配置后,Django就會幫我們自動上傳圖片。這個(gè)配置就是:

  • 首先你得定義一個(gè)存放文件的字段headImg = models.FileField(upload_to='./upload/'),當(dāng)然這里要指定文件存放路徑。
  • 然后你在表單中上傳文件后,用uf.cleaned_data['headImg']取得文件,再把它賦值給我們的模型字段`u.headImg。
  • 至此,我們點(diǎn)擊提交后,Django就幫我們把文件上傳到定義的存放文件的路徑中,然后把文件路徑賦值給headImg路徑。

11、等等——看標(biāo)題貌似應(yīng)該著重講解上傳之后怎么使用圖片的吧?可為什么快結(jié)束了還在講怎么上傳?。?/p>

耍勞資,484?

12、來了,來了……我們可以打印出來儲存在數(shù)據(jù)庫中的路徑,咦,是這個(gè)樣子的:

數(shù)據(jù)庫中的存儲路徑

13、我們直接在imgsrc中放這個(gè)路徑,試試。

<img src="{{user.headImg}}" alt=""/>

14、不行,圖片顯示的是:

圖片無法顯示

15、看看源代碼:

沒錯(cuò)啊,是我們儲存在數(shù)據(jù)庫中的路徑

16、莫非是絕對路徑和相對路徑的問題?試一試在前面給它加上http://127.0.0.1:8000/

<img src="http://127.0.0.1:8000/{{user.headImg}}" alt=""/>

17、仍然不行,這個(gè)時(shí)候源代碼顯示的路徑是這個(gè)樣子的,看樣子貌似已經(jīng)很完美了,但為什么就是不顯示了:

源代碼顯示的路徑

18、這個(gè)時(shí)候,樓主已經(jīng)逐漸喪失理智,覺得肯定是Django在玩我。但是樓主修煉多年,豈能因?yàn)檫@點(diǎn)小事失態(tài),于是樓主繼續(xù)各種stackoverflow,google,bing。有人說是因?yàn)樯厦孢@個(gè)看似完美的路徑也是一個(gè)url,Django里面處理url都是要經(jīng)過路由設(shè)置的,你在路由里面沒設(shè)置當(dāng)然它不知道你這個(gè)用來干嘛。

19、樓主頓時(shí)恍然大區(qū),說的真好,那我就去路由里面設(shè)置吧,添加一行:

url(r'upload/([*]+)'),

20、出錯(cuò)了,提示說這個(gè)需要2個(gè)參數(shù)。好吧,再給你個(gè)參數(shù):

url(r'upload/([*]+)', name='handleImgUrl'),

21、仍然提示出錯(cuò),需要2個(gè)參數(shù),Django仿佛在說:你TM在耍我么,給勞資一個(gè)name參數(shù)是幾個(gè)意思?

22、等等——我知道你想要一個(gè)下面這個(gè)樣子的:

url(r'upload/([*]+)', 'my_reg.views.XXX'),

23、但是,我TM不知道我寫出這么個(gè)XXX函數(shù)后,這個(gè)函數(shù)里寫什么啊。我這里只是要一個(gè)url路徑而已,你還得逼我寫個(gè)函數(shù),樓主長舒了一口氣,淡定——,寫就寫麼,大不了我這個(gè)XXX函數(shù)里面什么都都不寫,直接寫個(gè)pass什么的糊弄一下。

24、結(jié)果還是不行。呼——呼——,接下來該怎么辦?容樓主想想,圖片已經(jīng)上傳到服務(wù)器上了,現(xiàn)在全部問題就在怎么把它顯示出來,急死了,先上個(gè)廁所。

25、上廁所回來了,網(wǎng)上還說,設(shè)置一下MEDIA_URLMEDIA_ROOT,好吧,照著寫一下,在settings.py中加上這兩個(gè)配置,然后在urlpatterns中添加一下:

# 這是在settings中的設(shè)置
MEDIA_URL = '/upload/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'upload').replace("http://", "/")```

這是在urls.py中的設(shè)置

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)```

26、寫完這一切,樓主心里已經(jīng)完全沒底了,這TM也能行?因?yàn)闃侵髦皇窃O(shè)置了一下media路徑,貌似是告訴Django媒體文件在哪,然后Django就能自動在我們調(diào)用圖片的時(shí)候把圖片找出來并顯示。聽著想那么回事。

27、還是不行,容勞資捋一捋,不,容樓主捋一捋,樓主已經(jīng)亂了。唉,對了,貌似是我img里的src寫的不對,我現(xiàn)在還在用的是:

<img src="http://127.0.0.1:8000/{{user.headImg}}" alt=""/>

但是我們已經(jīng)設(shè)置了媒體路徑了,應(yīng)該Django會自動識別,不需要我們多此一舉寫那么多吧,刪掉變成下面那樣試試:

<img src="{{user.headImg}}" alt=""/>

28、還是仍然依然不行啊,這可怎么辦?樓主的實(shí)驗(yàn)看來是進(jìn)行不下去了啊,這么半途而廢實(shí)在不是樓主我的風(fēng)格啊,樓主該怎么辦?樓主根本不認(rèn)識什么Django牛人啊,不知道請教誰???而且這個(gè)貌似不是很難得事吧?這么請教別人是不是太沒面子了???樓主自學(xué)編程這么多年了,什么困難沒見過,今天是要撲街了么?要振作啊,樓主!

振作啊樓主

29、容樓主理理思路:這TM不就是個(gè)路徑嘛,路徑啊,url啊,懂不懂啊,相對路徑啊,絕對路徑啊,你傻逼啊你——咦,好像有人在罵我——我直接改改路徑試試,比如mysite/{{user.headImg}}或者/{{user.headImg}}或者./{{user.headImg}}或者mysite/{{user.headImg}},依然不行啊,這肯定是一個(gè)坑,既然是坑,樓主決定再潛心修行,一會再戰(zhàn)。

30、在看了N多文檔和文章之后,樓主好像懂了。也就是說上面第12步-第29步你可以忽略,直接從這里看怎么展示圖片。

31、首先,我們看看models.py里的模型,有個(gè)upload_to參數(shù),為了和過去一刀兩斷,樓主決定給upload_to賦值一個(gè)新的值叫avatar/,這個(gè)參數(shù)的意思是把文件上傳到MEDIA_ROOT/avatar/下面。

  • 既然這里upload_to的值是連接在MEDIA_ROOT/路徑后的一部分,所以很自然的只能寫成avatar/或者./avatar/,而不能寫成/avatar/,樓主已經(jīng)以身試法過。
  • 還有一點(diǎn),這里提到了MEDIA_ROOT,可是我們一直沒設(shè)置過啊。
headImg = models.FileField(upload_to='avatar/')

32、所以理所當(dāng)然的要設(shè)置MEDIA_ROOT,所以在settings.py中做如下設(shè)置,這里的意思就是說,我們在項(xiàng)目根目錄下會新建一個(gè)media文件夾,專門用來存放media文件。結(jié)合上面的設(shè)置可推出,我們上傳的文件會放在/media/avatar/下:

MEDIA_ROOT = os.path.join(BASE_DIR, 'media').replace("\\", "/")```

33、這`MEDIA_ROOT`就是媒體根目錄的路徑,這……好像是廢話。上傳的文件也會放在這里,但是正如我們上面探索時(shí)提到的:使用文件,實(shí)質(zhì)上也是調(diào)用了一個(gè)文件的url,在Django中提到url,都是要從`urlpatterns`中過濾一遍的。

34、所以,展示圖片的邏輯應(yīng)該是這樣的:我們調(diào)用圖片的url一般是有規(guī)律的,我們過濾的時(shí)候發(fā)現(xiàn),只要符合,就按照文件名從媒體根目錄中找相應(yīng)的文件。
- 所以,我們先找到圖片url的規(guī)律,都說了,圖片都是存在`/media/avatar/`中,也就是說圖片的路徑應(yīng)該是包含`/media/avatar/`的,為了保險(xiǎn)起見以及后續(xù)我們可能會存除了頭像之外的其他文件,比如儲存縮略圖的叫`/media/thumb/`,所以這里我們?nèi)〈蠹夜灿械腵/media/`作為過濾url的規(guī)律。

MEDIA_URL = '/media/'

- 這也就是為什么`MEDIA_ROOT`和`MEDIA_ROOT`經(jīng)常一起出現(xiàn),并且他們的有相同的值。

34、準(zhǔn)備好這些后,在`urlpatterns`中寫吧,這里寫的路由和普通的路由不一樣,因?yàn)槲覀冞@里的所有的媒體文件其實(shí)都是靜態(tài)文件的一部分,而且我們一般路由符合條件后是去執(zhí)行`views`中的某個(gè)函數(shù),這里卻是去某個(gè)文件夾中找文件,所以肯定寫法上是不同的,寫法是`static(如果符合這樣規(guī)律的url,就去這個(gè)目錄中找文件)`:

導(dǎo)入這兩個(gè)包

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)```

35、如果你之前在探索的時(shí)候經(jīng)常會看看瀏覽器會輸出什么錯(cuò)誤,你一般都是看到要么是404 error,要么就是500 error。為什么會出現(xiàn)404 error,就是因?yàn)槲覀兘o的圖片路徑?jīng)]有在urlpatterns中定義過,所以Django在要展示圖片的時(shí)候,一看,咦,這什么鬼url,在urlpatterns中根本沒有對應(yīng)的可以查,所以是錯(cuò)誤的請求網(wǎng)址,返回404 error。在urlpatterns中添加之后,就不會有404 error了。

36、好了,我們還剩下最后一步,就是在imgsrc中填寫正確的圖片地址。我們之前說了圖片是儲存在/media/avatar/下面的,所以圖片的路徑就是:

<img src="/media/{{user.headImg}}" alt=""/>
  • 你問為什么?因?yàn)槲覀儍Υ嬖跀?shù)據(jù)庫中的圖片路徑是upload_to的值和圖片名稱的拼接,比如下面的avatar/test_mini.jpg。
數(shù)據(jù)庫中儲存的圖片路徑

37、成功了!

用戶名和圖片的展示

38、瞧,解決方案中,在settings里設(shè)置MEDIA的相關(guān)屬性,然后在urlpatterns中設(shè)置相關(guān)路由,這些我們在之前的探索中都有嘗試,但就是差那么一點(diǎn)點(diǎn)。所以,如果我們不懂原理,僅僅照搬修改幾個(gè)設(shè)置,那么遠(yuǎn)遠(yuǎn)不能解決問題,雖然我們離答案曾經(jīng)那么近。

39、還有,為毛網(wǎng)上那么多教你上傳圖片的教程,就是沒有教你顯示圖片的教程呀喂!

我需要安慰

40、再見!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容