世界那么大,我想去看看。Django仿制微信朋友圈九宫格相册(1)

前面文章里的Python和Django知识点很重要,但过于零散。我们学习最终的目的还是应用。我们今天就来看下如何利用Django仿制微信朋友圈的九宫格相册。本教程比较长,会分成2部分发布,欢迎持续关注。我们会分享所有代码,并详细解读。读者需要对Python,Django, HTML, CSS和Javascript有一定的了解,否则读起来会比较吃力。


项目总体思路

对于此项目,我们总体开发思路是这样子的。

  • 用户在后台先创建相册,再上传图片。一个相册可以包含多张图片。

  • 对于单个相册,用户通过后台可以逐一上传单张图片或一次性上传压缩过的ZIP格式的图片包。

  • 用户上传的图片先调整成指定大小和格式再存储,同时生成缩略图存储。

  • 前端两个页面:一个展示相册列表,一个展示相册详情(包含所有图片)。

  • 前端缩略图通过九宫格显示给用户。当用户点击缩略图时,可以查看大图和放大。

  • 用户点击大图可以左右滑动查看上一张和下一张图片(触屏滑动效果)。

  • 图片是responsive的,大小随着浏览器尺寸变化而变化。


项目预期效果

展示相册列表

展示相册详情(微信朋友圈九宫格)


点击缩略图,显示大图,左右滑动。


项目开发所需安装包

除了Django 2.0, 你还需要通过pip安装pillow和django-imagekit两个库。pillow是python的图片库。django-imagekit可以对图片进行尺寸调整,生成缩略图或加水印。因为本项目主要是对图像进行操作,所以安装这两个库是必需的。


下面我们将正式开始本项目的教程。


第一步:创建gallery的应用,并修改配置文件。

利用Django创建一个叫gallery的应用,并把它加到settings.py中INSTALLED_APP里去。同时你应该把imagekit也加到INSTALLED_APP里去。代码如下所示:


INSTALLED_APPS = [
   'django.contrib.admin',
   
'django.contrib.auth',
   
'django.contrib.contenttypes',
   
'django.contrib.sessions',
   
'django.contrib.messages',
   
'django.contrib.staticfiles',
   
'gallery',
   
'imagekit',
]

因为我们要使用到静态文件和媒体文件,所以请在settings.py里设置STATIC_ROOT和MEDIA_ROOT.

STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR + '/static/'


# 设置媒体文件夹, 对于图片和文件上传很重要
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

最后请把gallery应用的urls也加到项目的urls里去,代码如下所示。

from django.contrib import admin
from django.urls import path, include


# 对于显示静态文件非常重要
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
   path('admin/', admin.site.urls),
   
path('gallery/', include('gallery.urls')),

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


第二步:创建模型models.py

我们需要创建两个模型,一个相册Album,一个图片AlbumImage。其中相册与图片之间是单对多的关系(ForeignKey)。我们通过upload_to指定了图片上传目的文件夹(/albums/)和缩略图目的文件夹((/albums/thumb/)。由于我们同时指定了媒体文件根目录MEDIA_ROOT(/media/), 所以最后图片都会上传到/media/albums/文件夹里。


代码如下所示。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.db import models
from imagekit.models import ProcessedImageField
from imagekit.processors import ResizeToFit
from django.urls import reverse


class Album(models.Model):
   title = models.TextField(max_length=1024)
   thumb = ProcessedImageField(upload_to='albums', processors=[ResizeToFit(300)], format='JPEG',
                               
options={'quality': 90})
   is_visible = models.BooleanField(default=True)
   create_date = models.DateTimeField(auto_now_add=True)
   mod_date = models.DateTimeField(auto_now=True)
   slug = models.SlugField(max_length=50, blank=True)

   def get_absolute_url(self):
       return reverse('gallery:album_detail', kwargs={'pk': self.pk, 'slug': self.slug})

 
def __str__(self):
       return self.title



class AlbumImage(models.Model):
   image = ProcessedImageField(upload_to='albums', processors=[ResizeToFit(1280)], format='JPEG',
                               
options={'quality': 70})
   thumb = ProcessedImageField(upload_to='albums/thumbs/', processors=[ResizeToFit(300)], format='JPEG',
                         
options={'quality': 80}, blank=True, null=True)
   album = models.ForeignKey('album', on_delete=models.PROTECT)
   alt = models.CharField(max_length=255, default='', blank=True)
   create_date = models.DateTimeField(auto_now_add=True)


   def __str__(self):
       return self.alt

你或许注意到我们使用了imagekit的ProcessedImageField,而不是django自带的ImageField。这里ProcessedImageField与ImageField类似,只不过你可以指定存储图片的大小,格式和质量。你上传的图片会先经由imagekit处理,再进行存储。缩略图thumb默认为空,因为你不需要上传,而直接由上传的image压缩生成。我们在后台会进行处理。


由于数据库里存储的是图片的链接,而不是图片本身。在模板里显示原图和缩略图,我们可以按如下代码操作。注: 一个item是一个AlbumImage对象。

<img src="{{ item.image.url }}" alt="{{ item.alt }}" />

<img src="{{ item.thumb.url }}"  />


第三步:编写urls.py

在gallery文件下新建urls.py, 加入如下代码。我们只需要两个URLs,一个展示相册列表,一个展示相册详情。

from django.urls import path, re_path
from . import views

# namespace
app_name = 'gallery'

urlpatterns = [

   re_path(r'^album/$', views.AlbumListView.as_view(), name='album_list'),
   
re_path(r'^album/(?P<pk>\d+)/(?P<slug1>[-\w]+)/$', views.AlbumDetail.as_view(), name='album_detail'),

]


第四步: 编写视图文件views.py

我们使用了Django自带的通用视图DetailView和ListView。如果你不懂什么是通用视图,请阅读Django视图详解

from django.views.generic import DetailView, ListView
from .models import Album, AlbumImage

class AlbumListView(ListView):

   queryset = Album.objects.filter(is_visible=True).order_by("-create_date")
   paginate_by = 1


class AlbumDetail(DetailView):

   model = Album

   def get_context_data(self, **kwargs):
       # Call the base implementation first to get a context
       
context = super().get_context_data(**kwargs)
       # Add in a QuerySet of all the images
       
context['images'] = AlbumImage.objects.filter(album=self.object.id)
       return context


在AlbumDetail里我们通过重写get_context_data向模板里传递了额外的参数images。这样我们在album_detail模板里就不仅能展示相册相关信息,也能展示属于该相册的所有图片了。


未完待续。下一部分我们着重讲解admin处理单个和多个图片上传,以及前端JS和CSS部分。

猜你喜欢

转载自blog.csdn.net/weixin_42134789/article/details/80656306