关于在Django中处理图像的详细指南

420 阅读9分钟

关于在Django中处理图像的详细指南

作为一名Web开发者,处理图片是一项重要的技能。Django是最流行的Web开发框架之一,它提供了方便处理图片的方法。

在本教程中,我们将建立一个处理图像的Django应用程序。通过构建它,你将学会如何设置你的Django项目环境来处理图片,以及如何对图片进行其他操作。

前提条件

要完成本教程,你需要具备以下条件。

  • Python和Django的基础知识。
  • 一个像Visual Studio Code这样的代码编辑器。

设置环境

我们将首先为我们的Django项目设置开发环境。

在你的命令行中,为我们的项目创建一个新的目录,并将其命名为Images ,如图所示。

mkdir Images

然后,进入该目录,创建一个虚拟环境,并分别用下面的命令激活它。

cd Images
py -m venv .venv
.venv\Scripts\activate.bat

现在,我们将需要安装以下库。

  • Django有助于使用Django网络开发框架建立我们的网站。
  • Pillow是一个图像库,我们将用它来处理我们的图像。
pip install django
pip install pillow

安装完成后,我们现在开始创建名为myGallery 的Django项目。

django-admin startproject myGallery
cd myGallery
py manage.py startapp demo

现在,我们需要在settings.py 文件中的已安装应用程序列表中注册我们的demo 应用程序,如图所示。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'demo', # new
]

我们需要告诉Django使用哪个URL来提供媒体文件,并指定存储图片的根目录。

我们将分别使用MEDIA_URLMEDIA_ROOT 来实现这一点。在settings.py 文件中,我们将添加以下内容。

import os

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

为了使用户在开发过程中能够上传图片,我们需要在我们的项目级urls.py ,为测试目的添加以下设置。它应该看起来像这样。

from django.contrib import admin
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static 

urlpatterns = [
    path('admin/', admin.site.urls),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) # New

上面的片段告诉Django,当项目仍处于开发阶段时,在哪里可以找到用户上传的图片。

创建和注册模型

我们现在可以继续并定义一个模型,该模型将用于在我们的应用程序中存储图片。

在Django中,一个默认的数据库会自动为你创建。你所要做的就是添加称为模型的表。

models.py ,我们将创建一个有两个字段的模型,即照片的titlephoto ,如图所示。

from django.db import models

class Image(models.Model):
    title = models.CharField(max_length=20)
    photo = models.ImageField(upload_to='pics')

upload_to 告诉Django将照片存储在media 目录下一个叫做pics 的目录中。

现在,我们可以在admin.py 中注册我们的模型,如图所示。

from django.contrib import admin
from .models import Image

class imageAdmin(admin.ModelAdmin):
    list_display = ["title", "photo"]

admin.site.register(Image, imageAdmin)

list_display 列表告诉Django管理员在管理仪表板上显示其内容。这些内容是模型的字段。

在这种情况下,我们希望它能显示每张上传的图片的titlephoto 字段。

显示图片

到目前为止,我们已经实现了使用Django管理员上传图片,但是我们还需要在我们的网站上显示这些图片。

所以,让我们添加显示模板、显示视图,并配置URL。

显示视图

Django中的视图是用来向服务器发送请求的。这些请求可以是返回一个页面,查询数据库,进行计算,等等。

views.py ,我们添加。

from django.shortcuts import render
from .models import Image

# Create your views here.
def index(request):
    data = Image.objects.all()
    context = {
        'data' : data
    }
    return render(request,"display.html", context)
  • 上述基于函数的视图将在请求时返回我们数据库中所有的Image 对象。

显示模板

在我们的应用程序demo ,我们将创建一个名为templates 的目录,并在其中创建一个名为display.html 的文件。

display.html 里面,我们将添加以下代码,以帮助显示所有上传的图片。

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

    <title>Demo Gallery</title>
  </head>
  <body class="container " style="padding-top: 5%;">
    <div class="row">
        {% for x in data %}
        <div class="col-md-4">
          <div class="thumbnail">
            <a href="{{ x.photo.url }}">
              <img src="{{ x.photo.url }}" alt="Lights" style="width:100%">
              <div class="caption">
                <p>{{ x.title }}</p>
              </div>
            </a>
          </div>
        </div>
        {% endfor %}
      </div>
  </body>
</html>

配置URLs

在项目层面(myGallery ),我们将添加一些代码,将根URL指向我们的演示应用程序的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('', include('demo.urls')) # new
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

现在,我们将在我们的demo 应用程序目录中创建一个名为urls.py 的文件。这个新的urls.py 文件应该包含我们应用程序的urlpatterns

向它添加以下代码。

from django.urls import path
from .import views

urlpatterns = [
    path('', views.index, name='index'),
]
  • 在上面的模式中,根路径('') 指向索引视图,作为回报,它将获得图片并与display.html 一起渲染。

测试

为了测试上传和显示是否正常,我们可以继续运行服务器。但是,在这之前,我们首先要在我们的数据库中进行迁移,然后创建超级用户。

在我们的cmd ,我们将继续运行。

py manage.py makemigrations
py manage.py migrate
  • makemigrations - 为新的 模型生成SQL命令。Images
  • migrate - 执行由 命令生成的SQL命令。makemigrations

现在我们可以使用下面的命令来创建我们的管理员账户。

py manage.py createsuperuser
  • createsuperuser - Django自带一个现成的管理站点,可以用来管理站点的用户和数据库。

当你运行这个命令时,你会被提示输入凭证以登录到你的账户。

运行以下命令,启动localhost服务器。

py manage.py runserver

管理网站中,添加一些图片,检查它们在显示页面上的显示情况。

在从我的个人电脑上添加四张图片,这是我的网页的样子。

display.html

现在我们已经看了处理图像的基本概念,接下来我们将进行高级概念的讨论。

用户图片上传

在这个案例中,我们将研究如何使用户使用表单上传图片。

在我们的应用程序级目录demo ,创建一个文件并将其称为forms.py 。在该文件中,我们将创建处理上传表单的类,并将其链接到我们的Image 模型,如图所示。

from django import forms
from .models import Image

class ImageUploadForm(forms.ModelForm):
    class Meta:
        model = Image
        fields = ['title', 'photo']

有了上述字段,Django将为我们呈现表单中的输入字段。

现在,让我们创建一个HTML表单来显示这些输入字段。在我们的templates 文件夹中,添加一个名为upload.html 的文件,并在其中添加以下代码。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image Upload</title>
</head>
<body>
    <form method="POST" enctype="multipart/form-data">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit"> Upload Image </button>
    </form>
</body>
</html>

在上述HTML表单中。

  • method="POST" 请求服务器接受表单的提交。
  • enctype="multipart/form-data" 以某种方式对文件进行编码,使它们能够通过 方法提交。POST
  • {% csrf_token %} 使我们能够保护网站免受跨网站请求伪造的影响。
  • {{ form.as_p }} 显示由段落的HTML标签包裹的表单字段。

接下来,我们将创建一个基于函数的视图,处理图片上传。在views.py ,更新你的代码,如图所示。

from django.shortcuts import render, redirect # new
from .models import Image
from .forms import ImageUploadForm # new 

def index(request):
    data = Image.objects.all()
    context = {
        'data' : data
    }
    return render(request,"display.html", context)
# new
def uploadView(request):                                      
    if request.method == 'POST':
        form = ImageUploadForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('index')
    else:
            form = ImageUploadForm()
    return render(request, 'upload.html', {'form': form})

在提交表单时,将检查该请求是否是POST 请求。如果是的话,将调用ImageUploadForm 来处理它。

然后,在保存表单并将用户重定向到显示页面之前,我们继续检查表单的有效性。

唯一剩下的部分是更新我们的urls.py 。在我们的应用程序级别的urls.py 文件中,如图所示更新它。

from django.urls import path
from .import views

urlpatterns = [
    path('', views.index, name='index'),
    path('upload_image/', views.uploadView, name= 'upload_image') # new
]
  • 新的路径upload_image指向负责上传过程的uploadView

下面是我的文件的样子。

upload.html

列出管理网站中的图像

到目前为止,我们的管理网站的图片是用它们的名字和路径列出的。

before

这使得我们很难在不点击链接的情况下识别图片。我们可以通过在仪表板上列出图片和它们的名字来轻松地改善这一点。

我们将在models.py 中编辑我们的Image 模型,添加一个image_tag 字段,以帮助呈现图片,如图所示。

from django.db import models
from django.utils.safestring import mark_safe # new

# Create your models here.
class Image(models.Model):
    title = models.CharField(max_length=20)
    photo = models.ImageField(upload_to='pics')

    def image_tag(self): # new
        return mark_safe('<img src="/../../media/%s" width="150" height="150" />' % (self.photo))
  • mark_safe 告诉Django模板将字符串渲染成这样(使用&lt;&gt; 将其渲染成文本)。因此,它为每张图片渲染了带有路径和尺寸的HTML图片标签。

现在,我们需要更新admin.py ,将image_tag 中的list_display

from django.contrib import admin
from .models import Image

class imageAdmin(admin.ModelAdmin):
    list_display = ["title", "image_tag", "photo"] # new

admin.site.register(Image, imageAdmin)

因此,我们的图像仪表板应该类似于这样。

after

创建缩略图

如果你点击显示页面中的图片,它们往往有不同的默认尺寸。大的图片甚至可能由于其尺寸而需要更长的时间来加载。

如果你想改变这种行为,给它们一个合理的尺寸,你就必须覆盖我们的图像模型中的save 方法。

我们将通过在上传过程中编辑图片的大小来创建缩略图,并将宽度和高度的最大值设置为300

让我们更新一下我们的models.py ,如图所示。

from django.db import models
from django.utils.safestring import mark_safe 
from PIL import Image as Im # new

# Create your models here.
class Image(models.Model):
    title = models.CharField(max_length=20)
    photo = models.ImageField(upload_to='pics')

    def image_tag(self):                     
        return mark_safe('<img src="/../../media/%s" width="150" height="150" />' % (self.photo))

    def save(self): # new
        super().save()
        img = Im.open(self.photo.path)
        # resize it
        if img.height > 300 or img.width > 300:
            output_size = (300,300)
            img.thumbnail(output_size)
            img.save(self.photo.path)

在Django模板中添加一个背景图片

我们将继续在我们的上传模板中添加一个背景图片。为此,我们将在我们的应用级目录demo ,创建一个名为static 的目录,并在其中添加你打算使用的背景图片。

我们使用的背景图片是bj.jpg

upload.html ,我们将在顶部加载静态内容,然后在body标签中添加背景图片。更新你的upload.html ,如图所示。

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image Upload</title>
</head>
<body  style="background-image: url('{% static 'bg.jpg' %}');">
    <form method="POST" enctype="multipart/form-data">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit"> Upload Image </button>
    </form>
</body>
</html>

之后,我们应将settings.py 中的STATIC_URL 从下面的第一个代码块改为第二个代码块。

STATIC_URL = 'static/'
STATIC_URL = '/static/'

这样,Django就能在static 文件夹中找到静态文件。

结语

最后,我们看了一个关于如何在Django中处理图片的实时代码实现。我们建立了一个Django项目,使用户可以上传图片并查看它们。此外,我们还让管理员能够查看图片的缩略图版本。

我希望你已经学会了如何在你的Django项目中实现这些解决方案。