django上傳圖片,ImageField
首先建立兩個model:
class Item(models.Model): name = models.CharField(max_length=250) description = models.TextField() class Meta: ordering = ['name'] def __unicode__(self): return self.name @models.permalink def get_absolute_url(self): return ('item_detail', None, {'object_id':self.id}) class Photo(models.Model): item = models.ForeignKey(Item) title = models.CharField(max_length=100) image = models.ImageField(upload_to='photos') caption = models.CharField(max_length=250, blank=True) class Meta: ordering = ["title"] def __unicode__(self): return self.title @models.permalink def get_absolute_url(self): return ('photo_detail', None, {'object_id':self.id}) class PhotoInline(admin.StackedInline): model = Photo class ItemAdmin(admin.ModelAdmin): inlines = [PhotoInline]
然後在settings.py中加入MEDIA_ROOT:
MEDIA_ROOT = '/var/www/gallery/media/'
由於我是用apache跑的,所以需要注意目錄許可權。
這裡
upload_to='photos' 這句表示上傳的檔案會存放在$MEDIA_ROOT/photos/ 下面,也就是放在 /var/www/gallery/media/photos/ 下。
之後一番syncdb,開啟admin頁面,看到剛才建立的model,新增一條資料,上傳圖片,成功了,django真是強大!
然後再修改剛才新增的那條記錄的修改介面,可以看到剛才上傳的圖片的超接:
點開圖片的超連結,卻顯示404 not found ,這可奇怪了,在伺服器上明明已經有這個檔案,並且資料庫都新增正確了,怎麼讀不回來呢。
這裡發現有個奇怪的地方,開啟的圖片url為:http://10.40.3.164:8090/admin/gallery/item/1/photos/github-logo.png/
超連結裡面的href值為:photos/github-logo.png,這個有問題啊,圖片應該是相對獨立的,且不說這裡load不到圖片,如果真實使用的時候,用這個url肯定不對。
好吧,看下ImageField 的原始碼吧。
在django/db/models/fields/files.py 中有:
class ImageField(FileField):
ImageField本身沒有什麼和 url有關的東西,繼續看它的父類: FileField
class FileField(Field): # The class to wrap instance attributes in. Accessing the file object off # the instance will always return an instance of attr_class. attr_class = FieldFile
FileField 中有個屬性 attr_class 這裡註釋說裡面屬性都是從這裡配置的那個類那來的。那我們繼續看 FieldFile 類:
class FieldFile(File):
def _get_url(self):
self._require_file()
return self.storage.url(self.name)
url = property(_get_url)
果然有個叫做 url 的屬性,但是這個屬性有是通過 storage.url方法返回的。由於是存的檔案,那很可能是FileStorage,先look一下吧。
在django/core/files/storage.py 中有個FileSystemStorage類,其中有個url方法:
def url(self, name):
if self.base_url is None:
raise ValueError("This file is not accessible via a URL.")
return urljoin(self.base_url, filepath_to_uri(name))
這裡的已經比較清楚了,url是由 self.base_url 加上一段檔案的filename組成的,這裡的 self.base_url 的值是由 MEDIA_URL 這個配置選項決定的,再看下 django/conf/global_setting.py 檔案,裡面的MEDIA_URL預設為空字串。
在我們專案的settings.py中加入 MEDIA_URL 這個配置選項:
MEDIA_URL='/media/'
重啟apache後,再次開啟那條記錄的修改頁面,這時候通過firebug看到超連結的href屬性已經變為 /media/photos/github-logo.png
點選超連結,請求的是 http://10.40.3.164:8090/media/photos/github-logo.png 頁面,好吧這就是href屬性是否以 “/" 開頭的不同。
但是此時還是顯示錯誤,但是問題已經很明顯了,和設定靜態檔案一樣,需要在專案的urls.py中加點東西:urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
OK,再試一下,圖片果然出來了。
至此,ImageField
已經可以使用了 :-)