One thing that I see the need for on almost every site is a place to put images. Whether it’s a band website, a personal homepage, or a school newspaper, there will be a need for a photo gallery. The easy way to do that is to use an open source package available already like Gallery2. But that’s written in PHP and it won’t integrate easily with the rest of your site–especially if you use Django as the framework for the rest of your site.
The solution: write a gallery application for use in your website. At first it may seem like a daunting task to create, but as I’ve found out, it can be quite easy. My implementation is not completely up and running yet, but that’s due to design issues with the rest of the site, not the photo gallery app itself. With no further adieu, let’s dive in and see how this can work.
class Album(models.Model):
name = models.CharField(maxlength=128)
slug = models.SlugField(prepopulate_from=("name",))
summary = models.TextField()
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
As you can see, this is the Album object which contains information about a set of associated photos. But wait, we don’t have photos created yet! Let’s do that now.
class Photo(models.Model):
title = models.CharField(maxlength=256)
summary = models.TextField(blank=True, null=True)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
image = models.ImageField(upload_to='photos/%Y/%m')
album = models.ForeignKey(Album)
is_cover_photo = models.BooleanField()
Ok so now we have albums which have photos, and photos have a lot of information like a file which contains an image, a title, and a summary.
Now that we have these objects, we have some choices to make. The images need to be resized into medium and small images for display on the list and detail pages, respectively. This can be done several ways:
Use the HTML width and height attributes to resize the images.
Create a Django view with width and height parameters to both resize and serve the images. (Lazy computation)
Resize the images on upload and store them to disk. (Upfront computation)
The first way is not optimal for two reasons. Firstly each picture must be downloaded in it’s entirety. This is inefficient and could upset people with less bandwidth or bandwidth limits. Secondly, when most browsers resize images, they do so using poor quality filters, resulting in a low quality representation of an image.
The second way is the most flexible, since the height and the width can be changed in a template or in a view and the resized images will change accordingly. However, there is more on-the-fly computation with this way, possibly increasing page load times. Also, Django is not designed to be used to serve binary files directly, so there could be unforseen consequences with handling a large number of photos this way.
The third way is less flexible, but it has one key advantage: it’s fast. Since the computation is done on upload, Apache or any other http media server can be used instead, completely removing the need to use the Django framework at all. Let’s implement it this way.
First, we’ll need to overload the save function of the Photo model:
def save(self):
if self.is_cover_photo:
other_cover_photo = Photo.objects.filter(album=self.album).filter(is_cover_photo = True)
for photo in other_cover_photo:
photo.is_cover_photo = False
photo.save()
filename = self.get_image_filename()
if not filename == '':
img = Image.open(filename)
img.thumbnail((512,512), Image.ANTIALIAS)
img.save(self.get_medium_filename())
img.thumbnail((150,150), Image.ANTIALIAS)
img.save(self.get_small_filename())
super(Photo, self).save()
Before I talk about the thumbnailing aspect of this function, I’d like to briefly explain what’s going on with the cover_photo aspect of Photo objects. Each Album has a cover photo, so if the Album needs to be represented, it can be represented by one special photo. This is just part of the way that I have designed my object, and can easily be removed. However, there is a small bit of obligatory boilerplate code in this save function which sets any other is_cover_photo attributes to False if necessary. (There can only be one cover photo per album, after all). I’ll come back to dealing with cover photos later.
First off, the if not filename == ” statement is needed because save is sometimes called with no image data, and that can and will throw exceptions if PIL is used on a None object. Then, it resizes a medium-sized (512px by 512px) image and saves it to a location provided by get_medium_filename. I leave it to you to define your own get_medium_filename and get_small_filename with your own naming convention. I followed Flickr’s example of an underscore followed by an argument (image001.jpg becomes image001_m.jpg for medium and image001_s.jpg for small). Finally, this method must call the it’s parent save method so that all of the other attributes are saved correctly.
Now that we’ve overloaded the save functionality, we are going to have a problem with deletion. Django will automatically delete the original image, but the resized thumbnails will be left on the disk forever. This is not a huge problem, but we don’t want that to happen anyways. So let’s take care of that by also overloading the delete function of Photo’s model:
def delete(self):
filename = self.get_image_filename()
try:
os.remove(self.get_medium_filename())
os.remove(self.get_small_filename())
except:
pass
super(Photo, self).delete()
Simply put, it deletes the thumbnail files and then calls it’s parent’s delete, which will in turn delete it’s original file.
Aside from creating some optional helper functions like get_small_image_url and/or get_medium_image_url, there’s not much more to be done with the Photo model. What can be done still, however, is in Album. We now have zero or one cover photos for each Album, but it’s going to be tricky to query for this each time, so let’s create a function in Album to help us retrieve the associated cover_photo Photo object:
def get_cover_photo(self):
if self.photo_set.filter(is_cover_photo=True).count() > 0:
return self.photo_set.filter(is_cover_photo=True)[0]
elif self.photo_set.all().count() > 0:
return self.photo_set.all()[0]
else:
return None
That is, if the Album has a photo with is_cover_photo == True, then grab it, otherwise grab the first image. If there are no images in the album, return None. That’s it for the models. Easy, huh? Just run manage.py syncdb, and let Django do the heavy lifting for you.
That’s all for part one of this series on writing a gallery application with Django. Next up: writing the views, urlconfs, and putting it all together. Templating will be left up to you, since there are so many ways to display this information, but some examples will be given to point you in the right direction.
Note to purists: I know that some of the functionality that is being implemented as helper functions in the models would be better implemented as custom template tags, but I find it easier to take a less philosophical stance on the "right" way to do things and sometimes do what’s more practical. In this case, writing model functions is a much easier solution than creating completely new template tags. In either case, moving to a new site will require a rewrite, so I’m not even convinced that it hurts reusability.
分享到:
相关推荐
《Python库Social-Auth-App-Django:深度解析与应用》 在Python的世界里,库是开发者们不可或缺的工具,它们极大地丰富了Python的功能并提高了开发效率。今天我们要深入探讨的是一个名为`social-auth-app-django`的...
3. **Django与App Engine集成**:这涉及到将Django项目配置为在App Engine上运行,可能需要修改WSGI服务器、设置环境变量、处理静态文件和媒体文件的存储,以及解决两者之间的兼容性问题。 4. **App Engine SDK**:...
Key FeaturesA beginners guide to learning python's most popular framework, DjangoBuild fully featured web projects in Django 2.0 through examples.Deploy web applications in quick and reliable fashion ...
**Python库 django-gallery-widget-1.2.1.dev0.tar.gz**\n\n在Python的世界里,库扮演着至关重要的角色,它们提供了丰富的功能,帮助开发者快速构建应用程序。`django-gallery-widget`是一个针对Python和Django框架...
资源分类:Python库 所属语言:Python 资源全名:social-auth-app-django-mongoengine-1.0.0.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
首先,确保在Django的app目录中已经正确地定义了数据模型,并且安装了所有需要的依赖包。创建app并定义models是使用Django的常规步骤。在app目录中,会有一个migrations目录用于存放迁移文件,这个目录应该包含至少...
Beginning Django Web App Dev with Python Beginning Django Web App Dev with Python
**PyPI 官网下载 | django_rename_app-0.1.1.tar.gz** 在Python的世界里,PyPI(Python Package Index)是官方的第三方软件包仓库,它为开发者提供了发布和分享他们创建的Python模块、库和其他工具的平台。用户可以...
SaaS App with Django, Stripe, Neon PostgreSQL, TailwindCSS, GitHub Actions
Part I Django’s Core Features Chapter 1 Starting a New Django Project: Building a Startup Categorizer with Blog Chapter 2 Hello World: Building a Basic Webpage in Django Chapter 3 Programming Django ...
【DJANGO-PART 1】:Django是Python编程语言中的一款强大且广泛使用的Web框架,它遵循模型-模板-视图(Model-Template-View,MTV)的设计模式,旨在简化网页应用的开发和维护过程。在本部分,我们将探讨Django的基础...
随后是“Writing your first Django app”,即编写你的第一个Django应用的教程,分为六个部分。这部分从创建一个Django项目开始,逐步介绍如何定义模型(models)、如何编写视图(views)、如何使用模板(templates...
- **Writing your first Django app, part 1-7 (编写你的第一个 Django 应用, 第 1 至 7 部分)**: 通过一系列教程引导读者完成一个完整的应用开发过程。 - **Advanced tutorial: How to write reusable apps (进阶...
python库。 资源全名:social-auth-app-django-1.2.0.tar.gz
This is a beginners Django course that will take you from absolute scratch to creating a simple Django web app. The course is a hands on course and i strongly advise you to follow along with me so you...
- **Writing your first Django app**: 这是一个分步骤的教程,它指导用户从零开始创建一个简单的Django应用,包括定义模型、视图、模板、表单等。 #### 2. 深入理解Django的核心概念 - **The model layer**: 模型...
4. **Tweetme\_app**:这个是Django应用,通常包含了models.py(数据模型)、views.py(视图逻辑)、forms.py(表单处理)、templates(模板文件)和static(静态资源)等。 **三、Django应用组件** 1. **数据模型...
编写第一个 Django 应用 (Writing your first Django app, part 1-7)** 这一系列教程通过实例详细介绍了如何创建一个简单的 Django 应用,包括创建模型、编写视图、设计模板等过程。 **4. 高级教程:编写可重用...