在自定义Django ImageField表单字段中访问实例值的DRY方法?
我正在使用 django-storages 来保存上传到 S3 的图片,我想创建一个自定义的表单字段,这样在编辑时可以显示图片,并且有一个选项可以更换它。
我遇到的问题是,存储在数据库中的路径值并不是图片的完整路径,因为 django-storages 会生成完整路径。
Settings.py:
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
AWS_STORAGE_BUCKET_NAME = 'myBucketName'
AWS_LOCATION = 'mySubBucketName'
models.py:
class MyModel(models.Model):
my_image = ImageField(upload_to='upload/path')
获取完整网址的示例:
>>> mymod = MyModel.objects.get(id=1)
>>> print mymod.my_image
upload/path/somefile.jpg
>>> print mymod.my_image.url
https://s3.amazonaws.com/myBucketName/mySubBucketName/upload/path/somefile.jpg
我不明白如何在自定义 Widget 中访问 mymod.my_image.url()(在这里我会渲染类似这样的内容:
class ImageViewWidget(forms.Widget):
markup = """
<img src="%(imagepath)"/>
<input type="file" name="%(name)s"/>
"""
def render(self, name, value, attrs=None):
output = self.markup % {
"name": name,
"imagepath": "<<<< MAGIC CODE GOES HERE >>>>"
}
return mark_safe(output)
更新:
我希望能以一种 DRY(不要重复自己)的方式来解决这个问题。很抱歉一开始没有说明这一点。
2 个回答
0
如果你使用 ModelForm 来生成表单,并且这个表单是通过小部件(widget)来显示的,那么你可以让这个小部件接收值,这样只需要写一次代码。
from django.forms import ModelForm, Textarea
class AuthorForm(ModelForm):
class Meta:
model = Author
fields = ('name', 'title', 'birth_date')
widgets = {
'name': Textarea(attrs={'cols': 80, 'rows': 20}),
}
所以在你的情况下,可能是这样的:
class MyModelForm(ModelForm):
class Meta:
model = MyModel
def __init__(self, *args, **kwargs):
image_url = ''
if self.instance:
image_url = self.instance.my_image.url
super(MyModelForm, self).__init__(*args, **kwargs)
self.fields['my_image'].widget=ImageViewWidget(path=image_url)
只要在创建 ModelForm 时设置了,self.instance 就可以访问到模型。
2
我觉得在你自定义的小部件里重写一下 __init__
方法,并把你的网址传进去就可以解决问题了。
补充:
class ImageViewWidget(forms.Widget):
def __init__(self, *args, **kwargs):
self.path = kwargs.pop('path', '')
super(ImageViewWidget, self).__init__(*args, **kwargs)
markup = """
<img src="%(imagepath)"/>
<input type="file" name="%(name)s"/>
"""
def render(self, name, value, attrs=None):
output = self.markup % {
"name": name,
"imagepath": self.path
}
return mark_safe(output)
class MyModelForm(ModelForm):
class Meta:
model = MyModel
def __init__(self, *args, **kwargs):
image_url = ''
if self.instance:
image_url = self.instance.my_image.url
super(MyModelForm, self).__init__(*args, **kwargs)
self.fields['my_image'].widget=ImageViewWidget(path=image_url)