Django 具有当前实例id的动态文件上载路径
我有一个表格,其中包含当前登录用户、一些输入和一个文件:Django 具有当前实例id的动态文件上载路径,django,file-upload,django-views,Django,File Upload,Django Views,我有一个表格,其中包含当前登录用户、一些输入和一个文件: class AddItemForm(ModelForm): class Meta: model = Item exclude = ['user'] 对于此表单,请查看: item_form = AddItemForm(request.POST, request.FILES) if item_form.is_valid(): item = item_form.save(commit=Fals
class AddItemForm(ModelForm):
class Meta:
model = Item
exclude = ['user']
对于此表单,请查看:
item_form = AddItemForm(request.POST, request.FILES)
if item_form.is_valid():
item = item_form.save(commit=False)
item.user = request.user
item.save()
对于此项目的文件字段,我使用上载功能。以下是我的观点:
class Item(models.Model):
user = models.ForeignKey(User)
cover_image = models.FileField(upload_to=get_upload_path)
def get_upload_path(instance, filename):
return "items/user_{user_id}/item_{item_id}/{filename}".format(user_id=instance.user.id, item_id=instance.id,filename=filename)
问题是,我无法在上载路径中看到当前实例id,因为以下行:
item = item_form.save(commit=False)
它还没有实例id,而是创建了user\u 1/item\u NONE/file来代替当前的item id
如何设置此路径的id
提前感谢我找到了基于使用post_保存信号的想法和代码,当创建的对象从临时目录移动到模型类中的指定目录时:
使用密钥和上传密钥是可选的。use_key默认为False。如果为True,则实例的id将用作新文件的前缀,因为现在我们正在移动该文件,因此有可能被覆盖。upload_to将简单地定义文件最初上载到的临时目录
更新至django新版本的新使用方式信号:
from django.db.models import ImageField, FileField, signals
from django.conf import settings
import shutil, os, glob, re
from distutils.dir_util import mkpath
class CustomImageField(ImageField):
"""Allows model instance to specify upload_to dynamically.
Model class should have a method like:
def get_upload_to(self, attname):
return 'path/to/{0}'.format(self.id)
"""
def __init__(self, *args, **kwargs):
kwargs['upload_to'] = kwargs.get('upload_to', 'tmp')
try:
self.use_key = kwargs.pop('use_key')
except KeyError:
self.use_key = False
super(CustomImageField, self).__init__(*args, **kwargs)
def contribute_to_class(self, cls, name):
"""Hook up events so we can access the instance."""
super(CustomImageField, self).contribute_to_class(cls, name)
signals.post_save.connect(self._move_image, sender=cls)
def _move_image(self, instance, **kwargs):
"""
Function to move the temporarily uploaded image to a more suitable directory
using the model's get_upload_to() method.
"""
if hasattr(instance, 'get_upload_to'):
src = getattr(instance, self.attname)
if src:
m = re.match(r"%s/(.*)" % self.upload_to, str(src))
if m:
if self.use_key:
dst = "%s/%d_%s" % (instance.get_upload_to(self.attname), instance.id, m.groups()[0])
else:
dst = "%s/%s" % (instance.get_upload_to(self.attname), m.groups()[0])
basedir = "%s/%s/" % (settings.MEDIA_ROOT, os.path.dirname(dst))
mkpath(basedir)
shutil.move("%s/%s" % (settings.MEDIA_ROOT, src),"%s/%s" % (settings.MEDIA_ROOT, dst))
setattr(instance, self.attname, dst)
instance.save()
def db_type(self):
"""Required by Django for ORM."""
return 'varchar(100)'
您不能在
get\u upload\u path
中为新记录使用instance.id
,因为此时尚未分配属性。它仅在更新现有记录时起作用。
from django.db.models import ImageField, FileField, signals
from django.conf import settings
import shutil, os, glob, re
from distutils.dir_util import mkpath
class CustomImageField(ImageField):
"""Allows model instance to specify upload_to dynamically.
Model class should have a method like:
def get_upload_to(self, attname):
return 'path/to/{0}'.format(self.id)
"""
def __init__(self, *args, **kwargs):
kwargs['upload_to'] = kwargs.get('upload_to', 'tmp')
try:
self.use_key = kwargs.pop('use_key')
except KeyError:
self.use_key = False
super(CustomImageField, self).__init__(*args, **kwargs)
def contribute_to_class(self, cls, name):
"""Hook up events so we can access the instance."""
super(CustomImageField, self).contribute_to_class(cls, name)
signals.post_save.connect(self._move_image, sender=cls)
def _move_image(self, instance, **kwargs):
"""
Function to move the temporarily uploaded image to a more suitable directory
using the model's get_upload_to() method.
"""
if hasattr(instance, 'get_upload_to'):
src = getattr(instance, self.attname)
if src:
m = re.match(r"%s/(.*)" % self.upload_to, str(src))
if m:
if self.use_key:
dst = "%s/%d_%s" % (instance.get_upload_to(self.attname), instance.id, m.groups()[0])
else:
dst = "%s/%s" % (instance.get_upload_to(self.attname), m.groups()[0])
basedir = "%s/%s/" % (settings.MEDIA_ROOT, os.path.dirname(dst))
mkpath(basedir)
shutil.move("%s/%s" % (settings.MEDIA_ROOT, src),"%s/%s" % (settings.MEDIA_ROOT, dst))
setattr(instance, self.attname, dst)
instance.save()
def db_type(self):
"""Required by Django for ORM."""
return 'varchar(100)'