回顾
我们在第一部分教程里创建了一个叫gallery的应用,编写了两个模型(相册和图片)。我们同时编写了两个URL及对应的视图处理方法,一个用来展示相册列表,一个用来展示相册详情。我们安装了第三方包pillow和imagekit,可以将上传的图片按指定大小和格式存储,并同时生成缩略图。
要完成整个项目,我们还需要:
编写后台admin.py,对上传的图片进行压缩,重命名并调整。如果用户上传压缩的图片包(zip格式),我们需要先解压,再调整图片格式进行存储。
编写模板显示相册列表和相册详情。这里我们需要利用Javascript和CSS实现九宫格效果以及大图的触屏滑动效果。
第五步: 编写后台admin.py
我们将通过Django自带的后台上传图片,所以需要对admin.py进行调整。我们需要先自定义上传表单forms.py, 然后在admin.py里使用它。我们的表单各个字段与模型Album保持一致,唯一区别是我们额外加了一个zip文件字段(见下图),该字段不是必需的。当客户在创建相册时就上传zip文件包时,我们解压文件处理图片,否则不管它。
fromdjangoimportforms
from.modelsimportAlbum
classAlbumForm(forms.ModelForm):
classMeta:
model = Album
exclude = []
zip = forms.FileField(required=False)
我们的admin.py做了很多事情,定义了我们所需要的字段。最重要的是我们重写了save_model方法,完成了对文件包的解压,图片的重命名及存储。
Django自带的save_model方法为admin界面用户保存model实例时的行为。request为HttpRequest实例,obj为model实例,form为ModelForm实例,change为bool值,取决于model实例是新增的还是修改的。以后我们会专题介绍admin.py后台的自定义与美化。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
importos
importuuid
importzipfile
fromdjango.contribimportadmin
fromdjango.core.files.baseimportContentFile
from.modelsimportAlbum,AlbumImage
from.formsimportAlbumForm
@admin.register(Album)
classAlbumModelAdmin(admin.ModelAdmin):
form = AlbumForm
prepopulated_fields = {'slug': ('title',)}
list_display = ('title','thumb')
list_filter = ('create_date',)
defsave_model(self,request,obj,form,change):
ifform.is_valid():
album = form.save()
ifform.cleaned_data['zip']is not None:
zip = zipfile.ZipFile(form.cleaned_data['zip'])
forfilenameinsorted(zip.namelist()):
file_name = os.path.basename(filename)
if notfile_name:
continue
data = zip.read(filename)
contentfile = ContentFile(data)
img = AlbumImage()
img.album = album
filename ='.jpg'.format(album.slug[:8],str(uuid.uuid4())[-13:])
img.alt = filename
img.image.save(filename,contentfile)
img.thumb.save('thumb-'.format(filename),contentfile)
img.save()
zip.close()
super().save_model(request,obj,form,change)
# In case image should be removed from album.
@admin.register(AlbumImage)
classAlbumImageModelAdmin(admin.ModelAdmin):
list_display = ('alt','album')
list_filter = ('album','create_date')
exclude = ['thumb']
defsave_model(self,request,obj,form,change):
ifform.is_valid():
img = form.save(commit=False)
slug = form.cleaned_data['album'].slug
filename ='.jpg'.format(slug[:8],str(uuid.uuid4())[-13:])
img.alt = filename
img.image.save(filename,form.cleaned_data['image'])
img.thumb.save('thumb-'.format(filename),form.cleaned_data['image'])
img.save()
super().save_model(request,obj,form,change)
我们为什么要重写save_model方法? 因为默认的方法总是满足不了我们的需求。
当我们通过AlbumForm创建album对象时,默认的form.save()方法只能将相关字段存入到Album模型对应的表单里。那我们上传的zip文件包里的图片怎么办?我们怎样把它解压后也存入AlbumImage模型对应的表单里?
我们希望在存储图片前对其重命名怎么办?默认的方式的按原文件名进行存储。
AlbumImage的thumb字段默认为空,我们怎么将用户上传的图片进行压缩处理后存入这个字段使其不为空?
如果你所有代码正确,你看到的后台创建相册和上传图片的admin应该分别如下所示。
第六步: 编写模板
我们将编写两个模板文件,一个album_list.html, 一个album_detail.html, 其具体文件位置如下所示:
我们album_list.html直接使用了bootstrap。更多内容见
可以重用bootstrap分页模板
。
#gallery/templates/gallery/album_list.html
相册
{#注释: page_obj不要改。#}
{% if page_obj %}
{% for album in page_obj %}
{{ album.title }}
{% endfor %}
{#注释:下面代码一点也不要动#}
{% if is_paginated %}
{% if page_obj.has_previous %}
Previous
{% else %}
class="page-link">Previous
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
class="page-link">{{ i }}class="sr-only">(current)
{% else %}
{{ i }}
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
Next
{% else %}
class="page-link">Next
{% endif %}
{% endif %}
{% else %}
{#注释:这里可以换成自己的对象#}
No albums yet
{% endif %}
为了实现触屏的效果,我们使用了JS前端框架photoswipe,代码如下。大部分代码你可以不看,你只需要读{% block content %}部分。
#gallery/templates/gallery/album_detail.html
{% load staticfiles %}
{% block css %}
{% endblock %}
{% block content %}
{% if album.is_visible %}
{{ album.title }}
{% for item in images %}
{% endfor %}
发布日期: {{ album.create_date |date:"Y-m-j" }}
{% else %}
目前相册不可见。
{% endif %}
{% endblock %}
{% block js %}
{% endblock %}
这时你看到的相册详情效果应该是这样子的。
啊?说好的九宫格效果呢。别急啊,我们还没用上css。在{% block css %}里加入下面代码。
大功告成。
点击缩略图,开始享受触屏滑动的大图效果吧。手机,pad和电脑上都非常流畅。
小编我写得怎么累?都不给我点个赞?
领取专属 10元无门槛券
私享最新 技术干货