我指的是这个youtube video,了解如何使用ImageField上传图片。他已经解释了如何在保存图像的同时使用instance.id
。我试过了,但instance.id
正在返回None
。而对他来说它完美无缺。以下是代码:
#models.py
import os
def get_image_path(instance, filename):
return os.path.join(str(instance.id), filename)
class AdProfile(models.Model):
name = models.CharField(max_length=100)
profile_image = models.ImageField(upload_to=get_image_path, blank=True, null=True)
每当保存文件时,保存为None/filename
。
即使这个link通知也是如此。我正在使用Django 10.5和MySQL数据库。
可能是什么问题?
答案 0 :(得分:6)
Django admin以某种方式调用了get_image_path函数而没有将模型保存到数据库,因此id为None。我们可以使用save方法覆盖django模型,并确保保存图像,get_image_path获取id为
的实例class AdProfile(models.Model):
name = models.CharField(max_length=100)
profile_image = models.ImageField(upload_to=get_image_path, blank=True, null=True)
# Model Save override
def save(self, *args, **kwargs):
if self.id is None:
saved_image = self.profile_image
self.profile_image = None
super(AdProfile, self).save(*args, **kwargs)
self.profile_image = saved_image
if 'force_insert' in kwargs:
kwargs.pop('force_insert')
super(AdProfile, self).save(*args, **kwargs)
答案 1 :(得分:1)
使用Raja Simon的答案,可以使用模型来处理模型中的所有FileField
class MyModel(models.Model):
file_field = models.FileField(upload_to=upload_to, blank=True, null=True)
def save(self, *args, **kwargs):
if self.id is None:
saved = []
for f in self.__class__._meta.get_fields():
if isinstance(f, models.FileField):
saved.append((f.name, getattr(self, f.name)))
setattr(self, f.name, None)
super(self.__class__, self).save(*args, **kwargs)
for name, val in saved:
setattr(self, name, val)
super(self.__class__, self).save(*args, **kwargs)
此外,我们可以使文件位置动态化,即不仅基于self.id,而且还基于外键的id或其他任何值。只需遍历字段并检查路径是否已更改。
def upload_to(o, fn):
if o.parent and o.parent.id:
return parent_upload_to(o.parent, fn)
return "my_temp_dir/{}/{}".format(o.id, fn)
class MyModel(models.Model):
parent = models.ForeignKey(Parent)
def save(self, *args, **kwargs):
# .... code from save() above here
for f in [f for f in self.__class__._meta.get_fields() if isinstance(f, models.FileField)]:
upload_to = f.upload_to
f = getattr(self, f.name) # f is FileField now
if f and callable(upload_to):
_, fn = os.path.split(f.name)
old_name = os.path.normpath(f.name)
new_name = os.path.normpath(upload_to(self, fn))
if old_name != new_name:
old_path = os.path.join(settings.MEDIA_ROOT, old_name)
new_path = os.path.join(settings.MEDIA_ROOT, new_name)
new_dir, _ = os.path.split(new_path)
if not os.path.exists(new_dir):
print "Making dir {}", new_dir
os.makedirs(new_dir)
print "Moving {} to {}".format(old_path, new_path)
try:
os.rename(old_path, new_path)
f.name = new_name
except WindowsError as e:
print "Can not move file, WindowsError: {}".format(e)
super(self.__class__, self).save(*args, **kwargs)