upload_to值更改photo.name属性

时间:2015-01-29 01:29:27

标签: python django

为什么upload_to值会更改photo.name的值?我正在尝试在运行时创建一个专辑目录,并在相应的专辑目录中编辑我的图像。我的代码能够使用相应的相册名称创建一个目录,并在其中包含正确的照片,但它会将self.photo.name更改为upload_to值。

在下图中。使用管理界面,我创建了一个名为test4的相册,我选择上传tumblr_nh09woLkmb1sfie3io1_1289.jpgself.photo.name的值为test4/tumblr_nh09woLkmb1sfie3io1_1289.jpg

在我的upload_path方法中,我也尝试了

   return instance.album.title
   return '/' + instance.album.title
   return instance.album.title + '/'

这不会创建名称为instance.album.title的目录,而是在我的MEDIA_ROOT文件中保存upload_path方法返回的名称。不是实际的文件名。

我觉得预期的self.photo.name应该是上传照片的名称。在这种情况下tumblr_nh09woLkmb1sfie3io1_1289.jpg

enter image description here

from django.db import models
from django.contrib import admin
from PIL import Image
from django.conf import settings
import os.path
from django.utils.html import format_html
from django.core.files.storage import FileSystemStorage
import re


class Album(models.Model):
    title = models.CharField(max_length=50, unique=True)

    def __str__(self):
        return self.title

    def images(self):
        lst = [x.photo for x in self.photo_set.all()]
        return lst

    def save(self, *args, **kwargs):
        # super(Album, self).save(*args, **kwargs)
        rgx = re.search(r'.*\w', self.title)
        self.title = rgx.group(0).replace(" ", "_")
        super(Album, self).save(*args, **kwargs)

class AlbumAdmin(admin.ModelAdmin):
    search_fields = ["title"]
    list_display = ["images"]

def upload_path(instance, filename):
    if " " in instance.album.title:
        instance.album.title.replace(" ", "_")
    return '/'.join([instance.album.title, filename])

class Photo(models.Model):
    title = models.CharField(max_length=50, blank=True)
    album = models.ForeignKey(Album)
    photo = models.ImageField(upload_to=upload_path)
    upload = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

    def size(self):
        return "%s x %s" % (self.photo.width, self.photo.height)

    def thumbnail(self):
        thumbnail_html = "<a href=\"{0}{1}\"><img border=\"0\" alt=\"\" src=\"{2}{3}\" height=\"40\" /></a>".format(settings.MEDIA_URL, self.photo.name, settings.MEDIA_URL, self.photo.name)
        print settings.MEDIA_URL, settings.MEDIA_ROOT
        return thumbnail_html

    thumbnail.allow_tags = True

class PhotoAdmin(admin.ModelAdmin):
    search_fields = ["title", "photo"]
    list_display = ["photo", "thumbnail", "title", "album", "size"]
    list_filter = ["album"]

4 个答案:

答案 0 :(得分:1)

关于upload_to函数的Django文档(https://docs.djangoproject.com/en/1.7/ref/models/fields/#django.db.models.FileField.upload_to)。

  

将附加到MEDIA_ROOT设置的本地文件系统路径,以确定url属性的值。

因此,如果您将upload_to指定为函数,Django将尝试将文件名保存为MEDIA_ROOT的相对路径。

答案 1 :(得分:1)

您有以下设置:

MEDIA_ROOT = os.path.join(BASE_DIR, "../media_root/Boothie/pics") 
MEDIA_URL = '/media/'

因此,每当您将upload_to传递给FileFieldImageField路径或函数时,它将以string_passed_to_upload_to/filename.ext格式保存在数据库中或由传递给它的函数。这样就可以重新创建文件的完整路径:MEDIA_ROOT + instance.photo.name和url:MEDIA_URL + instance.photo.name。这不是django的确切代码,只是为了给你一个想法。是否有意义?我可以通过一些例子详细说明。

修改

如果您希望只能获得基本文件名,可以执行os.path.split(photo.name)[1]。但无论如何,FileField都会将文件名存储在与MEDIA_ROOT路径相关的数据库中。 您还可以结帐django-smartfields应用,它具有该属性设置,因此如果您有型号:

from smartfields import fields

def upload_path(instance, filename):
    if " " in instance.album.title:
        instance.album.title.replace(" ", "_")
    return '/'.join([instance.album.title, filename])

class Photo(models.Model):
    title = models.CharField(max_length=50, blank=True)
    album = models.ForeignKey(Album)
    photo = fields.ImageField(upload_to=upload_path, keep_orphans=True)
    upload = models.DateTimeField(auto_now_add=True)

你可以这样使用它:photo.photo.name_base。确保您转到字段keep_orphans=True,否则它将删除旧文件。

答案 2 :(得分:1)

这可能对您有所帮助,在此示例中使用os.path.basename(self.file.name)而不是file.name。

class FileModel(models.Model):
    file = models.FileField(upload_to="images/")

    def __unicode__(self):
        return str(os.path.basename(self.file.name))

    @property
    def filename(self):
        return str(os.path.basename(self.file.name))

在模板文件中使用file.url

答案 3 :(得分:1)

class Photo(models.Model):

    def upload_path(self, name):
        return '{0}/{1}'.format(
            self.album.title,
            name.lower().replace(' ', '_').encode('trans')
        )

    photo = models.ImageField(upload_to=upload_path)

因此,如果您将upload_to定义为类方法,则可以按相关对象的字段&#39; title&#39;进行操作,例如将其作为子目录包含在图像路径中。