Django 模型 ImageField 字段的使用

一、系统环境

  • deepin 15.10.2 桌面版 64位
  • PyCharm Professional 2019.1.2
  • Django 2.2.4
  • Python 3.7.4

二、基本概念

class ImageField(upload_to = None, height_field = None, width_field = None, max_length = 100, **options)[source]

ImageField 是用于保存图像文件的字段。其基本用法和特性与 FileField 一样,只不过多了两个属性 height_field 和 width_field,分别保存图片的高度和宽度信息。默认情况下,该字段在 HTML 中表现为一个 ClearableFileInput 标签。在数据库内,我们实际保存的是一个字符串类型,默认最大长度 100,可以通过 max_length 参数自定义。真实的图片是保存在服务器的文件系统内的。

三、使用步骤

  • 配置 settings.py
# settings.py

# 配置 MEDIA_ROOT 作为你上传文件在服务器中的基本路径
MEDIA_ROOT = os.path.join(BASE_DIR, 'upload') # 注意此处不要写成列表或元组的形式
# 配置 MEDIA_URL 作为公用 URL,指向上传文件的基本路径
MEDIA_URL = '/media/'
# 这里特意写成 upload 和 media,而不是统一写成 media 或 upload,是为了便于理解 MEDIA_ROOT 和 MEDIA_URL 的作用和区别
  • models.py 中设置 ImageField 字段
# models.py

def user_directory_path(instance, filename):
    ext = filename.split('.').pop()
    filename = '{0}{1}.{2}'.format(instance.name, instance.identity_card, ext)
    return os.path.join(instance.major.name, filename) # 系统路径分隔符差异,增强代码重用性

class Student(models.Model):
    major = models.ForeignKey(Major, on_delete = models.CASCADE)
    name = models.CharField('姓名', max_length = 10)
    identity_card = models.CharField('身份证号', max_length = 20, unique = True)
    ......    
    # upload_to 参数接收一个回调函数 user_directory_path,该函数返回具体的路径字符串,图片会自动上传到指定路径下,即 MEDIA_ROOT + upload_to
    # user_directory_path 函数必须接收 instace 和 filename 两个参数。参数 instace 代表一个定义了 ImageField 的模型的实例,说白了就是当前数据记录;filename 是原本的文件名
    # null 是针对数据库而言,如果 null = True, 表示数据库的该字段可以为空;blank 是针对表单的,如果 blank = True,表示你的表单填写该字段的时候可以不填,但是对数据库来说,没有任何影响
    photo = models.ImageField('照片', upload_to = user_directory_path, blank = True, null = True)
    ......
    # 这里定义一个方法,作用是当用户注册时没有上传照片,模板中调用 [ModelName].[ImageFieldName].url 时赋予一个默认路径    
    def photo_url(self):
        if self.photo and hasattr(self.photo, 'url'):
            return self.photo.url
        else:
            return '/media/default/user.jpg'
  • 配置 urls.py
# 注意是项目根路由 urls.py 文件,而不是应用中的二级路由 urls.py 文件

# 方法一:
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    ......    
] + static(settings.MEDIA_URL, document_root = settings.MEDIA_ROOT)

# 方法二:
from django.urls import re_path
from django.conf import settings
from django.views.static import serve

urlpatterns = [
    ......
    # 注意是 media 而不是 upload
    re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),    
]
  • 配置 views.py
# views.py
from django.shortcuts import get_object_or_404
from .models import Major

def add_student(request):
    if request.method == 'POST':
        major = get_object_or_404(Major, pk = request.POST['major'])
        major.student_set.create(
            ......            
            photo = request.FILES.get('photo'),
        )
        ......
    ......
  • 模板中呈现图片
<!-- 调用的是 Student 模型中的 photo_url 方法,而不是直接调用 Student.photo.url。如果用户在注册时没有上传照片,后者会报错 -->
<img id="photo" src="{{ student.photo_url }}">

四、django-imagekit 的使用

imagekit 可以实现对上传图片的大小、质量、格式、水印、去边框等进行定制,功能很强大。

  • 准备工作
pip install pillow
pip install django-imagekit
# settings.py

INSTALLED_APPS = [
    'myapp',
    'imagekit', # 注册 imagekit
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
  • 配置 models.py
# models.py

from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFill
......

class Student(models.Model):
    ...... 
    photo = models.ImageField('照片', upload_to = user_directory_path, blank = True, null = True)
    photo_295_413 = ImageSpecField( # 注意:ImageSpecField 不会生成数据库表的字段
        source = 'photo',
        processors = [ResizeToFill(295, 413)],  # 处理成一寸照片的大小
        format = 'JPEG',  # 处理后的图片格式
        options = {'quality': 95}  # 处理后的图片质量
    )
    ......
    def photo_295_413_url(self):
        if self.photo_295_413 and hasattr(self.photo_295_413, 'url'):
            return self.photo_295_413.url
        else:
            return '/media/default/user.jpg'
# 默认情况下,imagekit 使用 imagekit.cachefiles.namers.source_name_as_path 来生成图片的路径
# 上例定制后的图片会上传到 [MEDIA_ROOT]/CACHE/images/[upload_to]/[md5处理后的名字.jpg]
# 想要自定义路径请参考 https://blog.csdn.net/weixin_42368421/article/details/84955946
  • 模板中呈现图片
<img id="photo" src="{{ student.photo_295_413_url }}">
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,729评论 6 517
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 95,226评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 169,461评论 0 362
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 60,135评论 1 300
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 69,130评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,736评论 1 312
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,179评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,124评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,657评论 1 320
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,723评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,872评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,533评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,213评论 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,700评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,819评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,304评论 3 379
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,876评论 2 361

推荐阅读更多精彩内容