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

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

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

1、創(chuàng)建一個(gè)項(xiàng)目名字叫mysite(要不是因?yàn)閼械闷鹈植囊澹趺纯赡芙衜ysite這么沒(méi)有創(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模型惋鹅,用來(lái)儲(chǔ)存用戶名和圖片……的路徑。

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ù)庫(kù)喂链。

python manage.py makemigratons
python manage.py migrate

6返十、然后我們就開(kāi)始寫路由url了,添加兩個(gè)url椭微,一個(gè)是注冊(cè)頁(yè)面洞坑,一個(gè)是注冊(cè)完成頁(yè)面∮剩看到下面這兩個(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、既然我們?cè)诼酚蓇rl里寫到了`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()

第一次打開(kāi)頁(yè)面不是POST請(qǐng)求,所以走else那條路监氢,創(chuàng)建一個(gè)form表單布蔗,然后在前臺(tái)顯示。第二次點(diǎn)擊“提交”按鈕是POST請(qǐng)求浪腐,走if那條路:意思就是這個(gè)表單請(qǐng)求內(nèi)容有files文件纵揍,然后如果它們有數(shù)據(jù),就存到數(shù)據(jù)庫(kù)中议街,并且把用戶名放在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ù)庫(kù)中的用戶信息吧雹,把用戶信息展示出來(lái)。

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頁(yè)面雄卷,一個(gè)是注冊(cè)頁(yè)面,一個(gè)是注冊(cè)完成頁(yè)面访得,我們簡(jiǎn)單搭建一下:

# 注冊(cè)頁(yè)面
...
    <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>
...```

注冊(cè)成功頁(yè)面

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

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

有種別走啊

10鳄炉、這個(gè)原理是:只要我們合理的配置后,Django就會(huì)幫我們自動(dòng)上傳圖片搜骡。這個(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é)束了還在講怎么上傳啊道逗?

耍勞資兵罢,484?

12滓窍、來(lái)了卖词,來(lái)了……我們可以打印出來(lái)儲(chǔ)存在數(shù)據(jù)庫(kù)中的路徑,咦吏夯,是這個(gè)樣子的:

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

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

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

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

圖片無(wú)法顯示

15杠园、看看源代碼:

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

16舔庶、莫非是絕對(duì)路徑和相對(duì)路徑的問(wèn)題抛蚁?試一試在前面給它加上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)逐漸喪失理智,覺(jué)得肯定是Django在玩我彬坏。但是樓主修煉多年朦促,豈能因?yàn)檫@點(diǎn)小事失態(tài),于是樓主繼續(xù)各種stackoverflow栓始,google务冕,bing。有人說(shuō)是因?yàn)樯厦孢@個(gè)看似完美的路徑也是一個(gè)url幻赚,Django里面處理url都是要經(jīng)過(guò)路由設(shè)置的禀忆,你在路由里面沒(méi)設(shè)置當(dāng)然它不知道你這個(gè)用來(lái)干嘛。

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

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

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

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

21胧瓜、仍然提示出錯(cuò),需要2個(gè)參數(shù)郑什,Django仿佛在說(shuō):你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ù)剃法,樓主長(zhǎng)舒了一口氣碎捺,淡定——,寫就寫麼贷洲,大不了我這個(gè)XXX函數(shù)里面什么都都不寫收厨,直接寫個(gè)pass什么的糊弄一下。

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

25漫仆、上廁所回來(lái)了捎拯,網(wǎng)上還說(shuō),設(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)完全沒(méi)底了懂扼,這TM也能行禁荸?因?yàn)闃侵髦皇窃O(shè)置了一下media路徑右蒲,貌似是告訴Django媒體文件在哪,然后Django就能自動(dòng)在我們調(diào)用圖片的時(shí)候把圖片找出來(lái)并顯示赶熟。聽(tīng)著想那么回事瑰妄。

27、還是不行映砖,容勞資捋一捋间坐,不,容樓主捋一捋邑退,樓主已經(jīng)亂了竹宋。唉,對(duì)了地技,貌似是我img里的src寫的不對(duì)蜈七,我現(xiàn)在還在用的是:

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

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

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

28、還是仍然依然不行啊作谚,這可怎么辦狡相?樓主的實(shí)驗(yàn)看來(lái)是進(jìn)行不下去了啊,這么半途而廢實(shí)在不是樓主我的風(fēng)格啊食磕,樓主該怎么辦?樓主根本不認(rèn)識(shí)什么Django牛人啊喳挑,不知道請(qǐng)教誰(shuí)氨蚵住?而且這個(gè)貌似不是很難得事吧伊诵?這么請(qǐng)教別人是不是太沒(méi)面子了暗グ蟆?樓主自學(xué)編程這么多年了曹宴,什么困難沒(méi)見(jiàn)過(guò)搂橙,今天是要撲街了么?要振作啊笛坦,樓主区转!

振作啊樓主

29、容樓主理理思路:這TM不就是個(gè)路徑嘛版扩,路徑啊废离,url啊,懂不懂啊礁芦,相對(duì)路徑啊蜻韭,絕對(duì)路徑啊悼尾,你傻逼啊你——咦,好像有人在罵我——我直接改改路徑試試肖方,比如mysite/{{user.headImg}}或者/{{user.headImg}}或者./{{user.headImg}}或者mysite/{{user.headImg}}闺魏,依然不行啊,這肯定是一個(gè)坑俯画,既然是坑析桥,樓主決定再潛心修行,一會(huì)再戰(zhàn)活翩。

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

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

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

32、所以理所當(dāng)然的要設(shè)置MEDIA_ROOT区匣,所以在settings.py中做如下設(shè)置偷拔,這里的意思就是說(shuō),我們?cè)陧?xiàng)目根目錄下會(huì)新建一個(gè)media文件夾亏钩,專門用來(lái)存放media文件莲绰。結(jié)合上面的設(shè)置可推出,我們上傳的文件會(huì)放在/media/avatar/下:

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

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

34茵瀑、所以,展示圖片的邏輯應(yīng)該是這樣的:我們調(diào)用圖片的url一般是有規(guī)律的躬厌,我們過(guò)濾的時(shí)候發(fā)現(xiàn)马昨,只要符合,就按照文件名從媒體根目錄中找相應(yīng)的文件扛施。
- 所以鸿捧,我們先找到圖片url的規(guī)律,都說(shuō)了疙渣,圖片都是存在`/media/avatar/`中匙奴,也就是說(shuō)圖片的路徑應(yīng)該是包含`/media/avatar/`的,為了保險(xiǎn)起見(jiàn)以及后續(xù)我們可能會(huì)存除了頭像之外的其他文件妄荔,比如儲(chǔ)存縮略圖的叫`/media/thumb/`泼菌,所以這里我們?nèi)〈蠹夜灿械腵/media/`作為過(guò)濾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)常會(huì)看看瀏覽器會(huì)輸出什么錯(cuò)誤荆针,你一般都是看到要么是404 error,要么就是500 error颁糟。為什么會(huì)出現(xiàn)404 error航背,就是因?yàn)槲覀兘o的圖片路徑?jīng)]有在urlpatterns中定義過(guò),所以Django在要展示圖片的時(shí)候棱貌,一看玖媚,咦,這什么鬼url婚脱,在urlpatterns中根本沒(méi)有對(duì)應(yīng)的可以查今魔,所以是錯(cuò)誤的請(qǐng)求網(wǎng)址勺像,返回404 error。在urlpatterns中添加之后错森,就不會(huì)有404 error了吟宦。

36、好了涩维,我們還剩下最后一步殃姓,就是在imgsrc中填寫正確的圖片地址。我們之前說(shuō)了圖片是儲(chǔ)存在/media/avatar/下面的瓦阐,所以圖片的路徑就是:

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

37踏幻、成功了!

用戶名和圖片的展示

38薄湿、瞧叫倍,解決方案中,在settings里設(shè)置MEDIA的相關(guān)屬性豺瘤,然后在urlpatterns中設(shè)置相關(guān)路由吆倦,這些我們?cè)谥暗奶剿髦卸加袊L試,但就是差那么一點(diǎn)點(diǎn)坐求。所以蚕泽,如果我們不懂原理,僅僅照搬修改幾個(gè)設(shè)置桥嗤,那么遠(yuǎn)遠(yuǎn)不能解決問(wèn)題须妻,雖然我們離答案曾經(jīng)那么近。

39泛领、還有荒吏,為毛網(wǎng)上那么多教你上傳圖片的教程,就是沒(méi)有教你顯示圖片的教程呀喂渊鞋!

我需要安慰

40绰更、再見(jiàn)!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锡宋,一起剝皮案震驚了整個(gè)濱河市儡湾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌执俩,老刑警劉巖徐钠,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異役首,居然都是意外死亡尝丐,警方通過(guò)查閱死者的電腦和手機(jī)显拜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)摊崭,“玉大人讼油,你說(shuō)我怎么就攤上這事∧佤ぃ” “怎么了矮台?”我有些...
    開(kāi)封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)根时。 經(jīng)常有香客問(wèn)我瘦赫,道長(zhǎng),這世上最難降的妖魔是什么蛤迎? 我笑而不...
    開(kāi)封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任确虱,我火速辦了婚禮,結(jié)果婚禮上替裆,老公的妹妹穿的比我還像新娘校辩。我一直安慰自己,他們只是感情好辆童,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布宜咒。 她就那樣靜靜地躺著,像睡著了一般把鉴。 火紅的嫁衣襯著肌膚如雪故黑。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天庭砍,我揣著相機(jī)與錄音场晶,去河邊找鬼。 笑死怠缸,一個(gè)胖子當(dāng)著我的面吹牛诗轻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播揭北,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼扳炬,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了罐呼?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤侦高,失蹤者是張志新(化名)和其女友劉穎嫉柴,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體奉呛,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡计螺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年夯尽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片登馒。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡匙握,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出陈轿,到底是詐尸還是另有隱情圈纺,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布麦射,位于F島的核電站蛾娶,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏潜秋。R本人自食惡果不足惜蛔琅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望峻呛。 院中可真熱鬧罗售,春花似錦、人聲如沸钩述。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)切距。三九已至朽缎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谜悟,已是汗流浹背话肖。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留葡幸,地道東北人最筒。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蔚叨,于是被迫代替她去往敵國(guó)和親床蜘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容