前言:
之前曾经写过的「阿里OSS」集成Django的基本配置及使用,里边在使用OSS是通过Django的两个信号量(signals)去实现的,一个post_init
获取保存动作前的图片,一个post_save
获取保存动作后的图片.通过对比两张图片,如果发生变化的话则将图片进行上传。
实现的思路没什么问题,在后期的使用过程中主要有如下两个问题发生:
post_init
信号会在除了保存动作以外的情况发生,这样一直对post_init
进行监听,对整个代码执行的效率有影响;- 如果项目中大量的
ImageField
都需要用到OSS的话,这样的信号量复用起来太糟糕。
解决思路:
- 通过自定义一个
ImageField
,从而更灵活去对OSS进行配置; - 找到
ImageField
对象在进行save
动作的方法,在其后上传图片即可。
实现:
自定义一个
ImageField
类:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import oss2
from django.db.models import ImageField
from django.conf import settings
class OssImageField(ImageField):
def pre_save(self, model_instance, add):
file = getattr(model_instance, self.attname)
if file and not file._committed: # 这行代码判断文件是否有改动
file.save(file.name, file.file, save=False)
# 以下代码块为自定义部分:上传到oss
auth = oss2.Auth(settings.ACCESS_KEY_ID, settings.ACCESS_KEY_SECRET)
bucket = oss2.Bucket(auth, settings.ALI_OSS_ENDPOINT, settings.ALI_BUCKET_NAME)
bucket.put_object_from_file('media/' + file.name, file.path)
return file使用:
由于
OssImageField
继承的是django的model中的ImageField
类,所以使用的时候就跟跟普通的Field一样使用,如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17...
class Designer(models.Model):
name = models.CharField(max_length=50, verbose_name="设计师名称")
country = models.CharField(max_length=50, verbose_name="国籍")
portrait = OssImageField(upload_to='designer/portrait/%Y/%m', verbose_name="肖像", help_text='尺寸500*500为宜')
bg_image = OssImageField(upload_to='designer/bg_image/%Y/%m', verbose_name="背景图片", help_text='尺寸1000*1000为宜')
desc = models.TextField(verbose_name='设计师描述')
class Meta:
verbose_name = '设计师'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
...关于OSS的基本配置请看上一篇文章
参考: