小程序动态

15502933391

咨询热线

用Django构建一个照片共享应用程序19图

Django是 Web 开发中最常用的 Python 框架。其内置功能和健壮的结构使其成为构建 Web 应用程序的绝佳选择。但是那里有太多的资源,有时将这些知识应用于现实世界的项目会让人不知所措。在本教程中,我们将构建一个全栈 Web 应用程序,在后端使用 Django,在前端使用 Bootstrap 风格化的 Django 模板。

要求

为了充分利用本教程,您最好掌握以下内容:

Python的基础知识Python中的面向对象编程Django Web 框架的基础知识

如果您之前没有使用 Django 的经验,请不要害怕继续学习本教程。这将是一个循序渐进的过程,并且将解释每个步骤。

在开始之前,我想向您介绍您最好的新盟友Django 文档。我们将在整篇文章中引用它,所以一定要熟悉它。

一个 Django 照片共享应用程序

本教程的所有源代码均可在此GitHub 存储库上找到。

项目的复杂性取决于我们想要包含的所有功能。我们想要为用户提供的功能越多,我们需要花费越多的时间来构建和集成所有内容到一个独特的项目中。

考虑到这一点,我们将看到我们将要构建的和我们不构建的之间的快速区别。

我们要构建什么

在本教程中,我们将构建一个全栈(后端和前端开发)照片共享应用程序。我们的应用程序将包括以下功能:

CRUD(创建、读取、更新、删除)数据库功能用户管理系统,使用户能够创建帐户、上传照片、查看其他人的照片以及编辑或删除自己的照片使用 Bootstrap 制作的简单 Web 界面

注意:虽然这个应用程序看起来很像一个社交网络,但它不是一个。像 Instagram 或 Twitter 这样的应用程序具有很多复杂性,无法在一篇文章中涵盖。

技术栈

让我们定义我们将要使用的技术。当我们需要使用它时,我们将涵盖每一个的安装过程。

在后端,Django 将是应用程序的核心框架。它允许我们通过 Django ORM(对象关系映射器)定义 URL、定义逻辑、管理用户身份验证和控制所有数据库操作。

此外,我们将使用几个第三方软件包来加速某些功能的开发。

Django-taggit为我们提供了通过几个步骤设置简单标签系统的能力。Pillow是一个 Python 包,提供 Django 图像处理功能。最后,Django-crispy-forms为我们提供了一种显示 Bootstrap 表单的简单方法。

在前端,我们将使用Django 模板语言,它由动态显示数据的 HTML 文件组成。

我们还将使用Bootstrap 5(撰写本文时的最新版本)来设计站点。

注意:您可以随时在requirements.txt文件中检查此项目中使用的依赖项。

创建一个 Django 项目

让我们从 Django 开始吧!

首先,确保你已经安装了 Python 3。大多数 Linux 和 macOS 系统已经安装了 Python,但如果您使用 Windows,您可以查看Python 3 安装指南。

注意:我们将在本教程中使用 Unix 命令(macOS 和 Linux)。如果您因任何原因无法执行它们,您可以使用图形文件管理器。

在某些 linux 发行版中,该python命令指的是 Python 2。在其他发行版中,python根本不存在。

让我们看看你需要使用什么 Python 命令来跟随。打开您的终端(在 Unix 上)或命令行窗口(在 Windows 上)并输入python --version:

python --version # My result Python 3.9.5

如果你有一个高于 3.6 的 Python 版本,你就可以开始了。如果您没有正确版本的 Python,您可能会收到如下消息之一:

Command python not found Python 2.7.18

跟随本教程需要运行的 Python 命令将是python3:

python3 --version Python 3.9.5 虚拟环境

一个虚拟环境是一个孤立的Python环境,其中包括所有你需要运行一个Python程序文件。

虚拟环境是任何 Python(和 Django)项目的重要组成部分,因为它们让我们可以与其他人管理和共享依赖项(项目依赖的外部包)。

为了在本地创建虚拟环境,我们将使用venvPython 3.6 或更高版本提供的内置模块。

以下命令将创建一个具有该名称的虚拟环境.venv(如果您愿意,可以选择其他名称):

python -m venv .venv

如果您使用的是 Ubuntu Linux 或任何其他基于 Debian 的发行版,您可能会收到以下消息:

The virtual environment was not created successfully because pip is not available ...

要解决此问题,您可以运行以下命令:

sudo apt-get install python3-venv

如果上面的命令不起作用,您可以使用virtualenv,这是另一个用于虚拟环境的库:

virtualenv .venv

运行此命令后,.venv将出现一个名为(或您选择的名称)的文件夹。

我们安装的所有软件包都将放置在该目录中。

要激活虚拟环境,您需要根据操作系统运行特定命令。您可以参考下表(摘自 Python 文档)。

平台

贝壳

激活虚拟环境的命令

POSIX

bash/zsh

$ 源.venv/bin/activate

$ 源.venv/bin/activate.fish

csh/tcsh

$ 源.venv/bin/activate.csh

PowerShell 核心

$ .venv/bin/Activate.ps1

视窗

命令行工具

C:> .venv\Scripts\activate.bat

电源外壳

PS C:> .venv\Scripts\Activate.ps1

由于我在 POSIX 操作系统上使用 bash shell,因此我将使用以下命令:

source .venv/bin/activate

请注意,.venv一旦我激活了virtualenv.

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

安装 Django

Django 是一个外部包,所以我们需要使用 pip 安装它:

pip install django # Use pip3 if the command above doesnt work pip3 install django

注意:我们可以随时查看我们的venvwith 中安装的软件包pip freeze。

接下来,让我们config使用命令行实用程序django-admin启动一个名称为 Django 的项目。

django-admin startproject config

这里config是项目的名称,它用作命名约定以保持所有项目具有相同的结构。例如,Django cookiecutter使用这个约定名称来启动一个项目。

话虽如此,您可以使用任何其他名称创建项目。

运行这些命令后,您应该拥有 Django 项目的常规文件结构。您可以使用命令行实用程序树或任何文件管理器进行检查。

注意:如果您无法运行tree,则需要安装它。

$ tree config/ └── config ├── config │ ├── asgi.py │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── manage.py

现在让我们用 进入项目文件夹cd,并运行服务器以检查一切是否正确设置:

cd config/ python manage.py runserver

您将看到一条警告消息,指出存在未应用的迁移。这是一条完全正常的消息,我们将在“创建照片模型”部分学习如何运行迁移。

现在,在浏览器中访问localhost:8000。您应该会看到标志性的 Django 祝贺页面。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

启动照片共享应用程序

该manage.py文件具有完全相同的功能为django-admin,所以我们将在本教程中使用了很多次。

它的位置在项目的根文件夹中,每次我们想用它运行一个命令时,都需要进入项目目录。

请记住始终列出您所在目录的文件ls,以检查我们是否在正确的位置:

$ ls Another-files.. manage.py

记住这些提示后,是时候启动项目的主应用程序了。为此,我们打开一个新的 shell(因此本地服务器仍在运行),并使用manage.py命令startapp。

注意:每次我们打开一个新的 shell 会话时,我们都需要再次激活虚拟环境。

source .venv/bin/activate cd config python manage.py startapp photoapp

在这种情况下,应用程序的名称是photoapp。再一次,您可以使用您想要的任何名称创建它。

每次我们创建一个应用程序时,我们都必须安装它。我们可以config/settings.py通过添加photoapp到INSTALLED_APPS变量来在文件中执行此操作:

# config/settings.py INSTALLED_APPS = [ django.contrib.admin, ... # Custom apps photoapp, ]

接下来,我们将进入 app 目录并创建一个空urls.py文件。我们可以通过运行touch或使用图形文件管理器创建它来做到这一点:

cd photoapp/ touch urls.py

最后,让我们在整个项目中包含照片共享应用程序的所有 URL 模式。为此,我们将使用该django.urls.include函数:

# config/urls.py from django.urls import path, include # Import this function urlpatterns = [ path(admin/, admin.site.urls), # Main app path(, include(photoapp.urls)), ]

上面的代码将包含项目的所有 URL 模式photoapp/urls.py。

如果您查看运行服务器的 shell,您会看到一个错误:

raise ImproperlyConfigured(msg.format(name=self.urlconf_name)) ....

那是因为我们还没有在文件中创建urlpatterns列表photopp/urls.py。

要解决此问题,请创建一个名为 的空列表urlpatterns。我们稍后将使用 Django 路径填充该变量:

# photoapp/urls.py # Empty patterns urlpatterns = [ ]

注意:使用这种方法的优点是我们可以通过在其中包含所有需要的代码来使 photoapp 可重用。

创建照片模型

在本节中,我们将构建应用程序的数据库模式。为此,我们将使用 Django ORM。

Django ORM 允许创建和管理数据库表,而无需手动使用 SQL。

当我们写一个模型时,它代表一个数据库表,其中的每个属性代表一个列。

由于我们将使用 Django 内置身份验证系统,我们可以开始关注应用程序的核心功能。这样,我们就可以避免构建自定义用户管理系统。

在开始之前,我们将安装一些第三方软件包,django-taggit以及Pillow. 我们可以使用以下命令执行此操作:

pip install django-taggit Pillow

django-taggit是一个 Django 应用程序,所以我们需要像安装photoapp一样安装它:

# config/settings.py INSTALLED_APPS = [ ... # 3rd party apps taggit, # Custom apps photoapp, ] # Django taggit TAGGIT_CASE_INSENSITIVE = True

该TAGGIT_CASE_INSENSITIVE变量将标签配置为不区分大小写。这意味着PYTHON并且python将是相同的。

让我们定义Photo模型,它将成为应用程序的主要模型。打开photoapp/models.py文件并使用以下代码:

# photoapp/models.py from django.db import models from django.contrib.auth import get_user_model from taggit.managers import TaggableManager class Photo(models.Model): title = models.CharField(max_length=45) description = models.CharField(max_length=250) created = models.DateTimeField(auto_now_add=True) image = models.ImageField(upload_to=photos/) submitter = models.ForeignKey(get_user_model(), on_delete=models.CASCADE) tags = TaggableManager() def __str__(self): return self.title

在上面的代码块中,我们定义了Photo模型。让我们看看每个字段的作用。

该title字段是一个CharField,限制为 45 个字符。description 是另一个 CharField 但限制为 250 个字符。created是一个DateTimeField,顾名思义,它存储创建照片时的日期和小时。image是一个ImageField。它将图像上传到media/photos并存储文件所在的 URL。稍后我们将看到如何设置媒体文件。submitter是一个ForeignKey,这意味着它与用户和上传的照片有关。这样我们就可以过滤哪个用户上传了一张照片。最后,tags是一个TaggableManager,允许我们通过标签对主题进行分类。

另一方面,该__str__方法指示每个对象将如何显示在管理区域中。稍后,我们将设置管理员并创建我们的第一个对象。

要基于我们创建的模型创建数据库,我们首先需要进行迁移,然后运行它们。

进入项目根目录并使用manage.py带有以下参数的脚本:

python manage.py makemigrations python manage.py migrate

该makemigrations命令将根据Photo模型创建一个迁移文件。

注意:迁移是基于模型在数据库中产生更改的 Python 脚本。

我们可以通过打开photoapp/migrations/0001_initial.py文件确切地看到迁移发生了什么

# photoapp/migrations/0001_initial.py # imports ... class Migration(migrations.Migration): initial = True dependencies = [ (taggit, 0003_taggeditem_add_unique_index), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( name=Photo, fields=[ (id, models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name=ID)), .....

提示:切勿手动修改迁移文件。所有迁移都必须由 Django 自动生成。

该migrate命令通过运行所有迁移来创建数据库表。

运行这两个命令后,您应该会在项目根文件夹中看到一个 SQLite 数据库。如果我们使用DB Browser检查它,我们将看到与Photo模型相关的所有字段。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

管理开发中的媒体文件

照片共享应用在很大程度上依赖于媒体文件。这完全是关于共享图像,不是吗?

Django 中的媒体文件是用户上传的所有文件。现在,我们将在开发中设置媒体文件,因为我们只会通过本地服务器与应用程序交互。

为了在开发中启用媒体文件,我们在设置文件中创建MEDIA_URL和MEDIA_ROOT变量。此外,我们需要修改urlpatterns整个项目的 以从本地服务器提供媒体文件。

首先,我们需要编辑config/settings.py文件并在文件末尾附加以下代码:

# config/settings.py # Other settings ... MEDIA_URL = /media/ MEDIA_ROOT = BASE_DIR / media/

MEDIA_URL是处理上传到MEDIA_ROOT文件夹的所有媒体的 URL 。在这种情况下,绝对媒体 URL 将如下所示::8000/media/。

另一方面,MEDIA_ROOT是指向放置所有媒体的文件夹的路径。

请记住,由于我们使用的是pathlib库,因此我们可以将路径与/.

我们可以MEDIA_ROOT将图像视为上传图像的物理存储,以及MEDIA_URL指向该存储的 URL。

如果我们想让 Django 管理媒体文件,我们需要修改项目 URL:

# config/urls.py # New imports from django.conf import settings from django.conf.urls.static import static urlpatterns = [ path(admin/, admin.site.urls), # Main app path(, include(photoapp.urls)), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

考虑到这一点,上传照片的绝对 URL 将是::8000/media/photos/。这是因为我们将upload_to属性设置为photos/.

注意:接受用户上传的文件可能很危险。查看此安全注意事项列表。

在使用公开可用的应用程序时,我们必须小心处理媒体文件。我们可能会遭受DoS 攻击。用户也可能上传恶意内容,因此推荐的方法是始终使用CDN来解决此类问题。

现在,您可以忘记安全问题,因为我们正在处理一个开发项目,并且ImageField只接受一组预先确定的扩展。

您可以通过在 Django shell 中运行以下代码来检查那些有效的扩展(确保您的venv已激活):

$ python manage.py shell >>> from django.core.validators import get_available_image_extensions >>> get_available_image_extensions() [blp, bmp, dib, bufr, cur, pcx, dcx, dds, ps, eps, fit, fits, fli, flc, ftc, ftu, gbr, gif, grib, h5, hdf, png, apng, jp2, j2k, jpc, jpf, jpx, j2c, icns, ico, im, iim, tif, tiff, jfif, jpe, jpg, jpeg, mpg, mpeg, mpo, msp, palm, pcd, pdf, pxr, pbm, pgm, ppm, pnm, psd, bw, rgb, rgba, sgi, ras, tga, icb, vda, vst, webp, wmf, emf, xbm, xpm] 使用 Django Admin 测试模型

Django admin 是一个内置界面,管理用户可以在其中使用项目的注册模型进行 CRUD 操作。

现在我们已经创建了照片模型并设置了媒体文件,是时候Photo通过管理页面创建我们的第一个对象了。

为此,我们必须将Photo模型注册到管理页面。让我们打开photoapp/admin.py,导入 Photo 模型,并将其作为参数传递给admin.site.register函数:

# photoapp/admin.py from django.contrib import admin from .models import Photo # We import the photo model # Register your models here. admin.site.register(Photo)

接下来,是时候创建一个能够访问管理页面的超级用户了。我们可以使用以下命令执行此操作:

python manage.py createsuperuser Username: daniel Email address: Password: Password (again): Superuser created successfully

由于我们使用的是默认的 auth 用户,因此您现在可以不使用电子邮件离开超级用户。

创建超级用户后,跳转到浏览器并导航到:8000/admin。

它会将您重定向到登录页面,您需要在其中填写您的凭据(创建用户时使用的凭据)。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

输入凭据后,我们将可以访问一个简单的仪表板,在那里我们可以开始创建照片。只需点击照片部分,然后点击添加按钮。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

下面是填充创建字段的样子。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

只需拖放即可上传图像。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

点击保存按钮后,我们将看到一个包含所有创建照片的仪表板。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

使用视图处理 Web 响应

我们已经定义了一个工作应用程序的数据库架构,甚至使用 Django 管理员创建了一些对象。但是我们还没有触及任何网络应用程序最重要的部分——与用户的交互!

在本节中,我们将构建照片共享应用程序的视图。

从广义上讲,视图是接受请求并返回响应的 Python 可调用(类或函数)。

根据Django 文档,我们应该将所有视图views.py放在每个应用程序内命名的文件中。这个文件在我们启动应用程序时已经创建。

我们有两种主要的方法来创建视图:使用基于函数的视图 (FBV) 或基于类的视图 (CBV)。

CBV是重用代码的最佳方式——通过将 Python 类继承的强大功能应用到我们的视图中。

在我们的应用程序中,我们将使用通用视图,它允许我们通过继承 Django预构建类来创建简单的 CRUD 操作。

在开始之前,我们将导入构建视图所需的所有内容。打开photoapp/views.py文件并粘贴以下代码:

# photoapp/views.py from django.shortcuts import get_object_or_404 from django.core.exceptions import PermissionDenied from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.urls import reverse_lazy from .models import Photo

让我们看看我们在这里导入了什么

get_object_or_404是一种快捷方式,允许我们从数据库中检索对象,防止DoesNotExists错误并引发 HTTP 404 异常。PermissionDenied 调用时引发 HTTP 403 异常。预构建的generic视图帮助我们用几行代码构建 CRUD 功能。我们将使用LoginRequiredMixin和UserPassesTestMixin来断言用户在访问视图时具有正确的权限。reverse_lazy 在 CBV 中用于将用户重定向到特定 URL。我们需要导入Photo以检索和更新数据库行(照片对象)。

注意:您可以访问GitHub 上的views.py文件。

照片列表视图

通用列表视图将帮助我们显示模型的许多对象。我们将与DetailView后者进行比较。

在本节中,我们将构建两个主要视图。将PhotoListView任何用户上传的所有照片作为上下文传递,并PhotoTagListView以标签 slug 作为参数来显示照片。

下面的代码定义了PhotoListView继承自ListView:

# photoapp/views.py class PhotoListView(ListView): model = Photo template_name = photoapp/list.html context_object_name = photos

首先,我们继承ListView并因此从该类接收所有行为。

请记住,您始终可以在官方 GitHub 存储库中查看任何 Django 类的源代码。

然后我们定义我们从中读取数据的模型、我们将使用的模板(我们稍后将构建前端)以及我们可以用来访问模板中的数据的上下文对象的名称。

现在,是时候声明PhotoTagListView. 这个视图有点复杂,因为我们必须使用get_queryset()和get_context_data()方法:

# photoapp/views.py class PhotoListView(ListView): ... class PhotoTagListView(PhotoListView): template_name = photoapp/taglist.html # Custom method def get_tag(self): return self.kwargs.get(tag) def get_queryset(self): return self.model.objects.filter(tags__slug=self.get_tag()) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["tag"] = self.get_tag() return context

在这里,我们继承了PhotoListView. 这意味着我们使用相同的modeland context_object_name,但我们正在更改template_name.

此视图可能与前一个视图相同,只是我们处理的是自定义方法。

我们正在创建一个自定义方法get_tag来从 Django 将要接受的响应中接收标签 slug 并返回它。我们这样做是因为我们将在两个地方使用该函数。

该get_queryset方法self.model.objects.all()默认设置为返回。我们对其进行了修改,使其仅返回带有传递给 URL 的 slug 标记的照片对象。

最后,get_context_data修改为还返回传递给 URL 的标记。这是因为我们稍后会在模板中显示它。

照片细节视图

此视图是一个简单的视图DetailView,显示与唯一照片相关的所有数据。这包括所需照片的标题、描述和标签:

# photoapp/views.py class PhotoListView(ListView): ... class PhotoTagListView(PhotoListView): ... class PhotoDetailView(DetailView): model = Photo template_name = photoapp/detail.html context_object_name = photo

我们执行的过程与我们对列表视图所做的过程几乎相同。唯一的区别是我们返回的是单个对象而不是多个对象,并且使用了不同的模板。

创建照片视图

此视图仅允许用户在登录后创建照片对象。我们不希望匿名用户能够将内容上传到我们的平台。那会很可怕!

保护Django的这一功能最简单的方法是创建一个类继承CreateView和LoginRequiredMixin。该LoginRequiredMixin测试用户是否登录如果用户没有在,他们将被重定向到登录页面(我们将在以后的版本)登录:

# photoapp/views.py class PhotoListView(ListView): ... class PhotoTagListView(PhotoListView): ... class PhotoDetailView(DetailView): ... class PhotoCreateView(LoginRequiredMixin, CreateView): model = Photo fields = [title, description, image, tags] template_name = photoapp/create.html success_url = reverse_lazy(photo:list) def form_valid(self, form): form.instance.submitter = self.request.user return super().form_valid(form)

按照这种观点,Django会创建一个表单title,description,image和tags领域。

我们也在使用该sucess_url属性。如果照片创建成功,用户将被重定向到照片仪表板。

如果我们仔细查看该form_valid方法,我们会注意到它将发出请求的用户设置为照片表单的提交者。

更新和删除照片视图

我们希望用户只有在提交者才能修改或删除照片。

如果我们使用 CBV,处理条件身份验证可能会很困难。但是,我们可以利用TestMixins来完成此任务。

让我们创建一个测试 mixinUserIsSubmitter来检查尝试更新或删除照片的用户是否实际提交了它:

# photoapp/views.py class PhotoListView(ListView): ... class PhotoTagListView(PhotoListView): ... class PhotoDetailView(DetailView): ... class PhotoCreateView(LoginRequiredMixin, CreateView): ... class UserIsSubmitter(UserPassesTestMixin): # Custom method def get_photo(self): return get_object_or_404(Photo, pk=self.kwargs.get(pk)) def test_func(self): if self.request.user.is_authenticated: return self.request.user == self.get_photo().submitter else: raise PermissionDenied(Sorry you are not allowed here)

首先,我们创建了一个自定义方法get_photo,该方法返回一个 Photo 对象,其主键在 URL 中指定。如果照片不存在,则会引发 HTTP 404 错误。

然后我们定义了测试函数。如果用户已登录并且是照片提交者,它只会返回 true。

如果用户未登录,则会引发PermissionDenied异常。

在另一方面,PhotoUpdateView并且PhotoDeleteView是我们创建的混入的孩子,也UpdateView和DeleteView分别为:

# photoapp/views.py class PhotoListView(ListView): ... class PhotoTagListView(PhotoListView): ... class PhotoDetailView(DetailView): ... class PhotoCreateView(LoginRequiredMixin, CreateView): ... class UserIsSubmitter(UserPassesTestMixin): ... class PhotoUpdateView(UserIsSubmitter, UpdateView): template_name = photoapp/update.html model = Photo fields = [title, description, tags] success_url = reverse_lazy(photo:list) class PhotoDeleteView(UserIsSubmitter, DeleteView): template_name = photoapp/delete.html model = Photo success_url = reverse_lazy(photo:list)

在PhotoUpdateView继承了测试功能UserIsSubmitter混入,并从更新功能UpdateView。

该fields属性定义了用户将能够编辑的字段。我们不希望更改图像,也不希望更改创建日期或提交者。

另一方面,PhotoDeleteView也继承了测试功能,但删除了照片而不是更新它。

如果一切顺利,两个视图都将用户重定向到列表 URL。

这就是所有的意见。现在,让我们创建一个简单的身份验证应用程序并完成项目。

网址模式

我们快到了。我们已经定义了数据库架构以及用户将如何创建和更新照片。让我们看看如何处理照片共享应用程序的 URL 配置。

还记得我们在urlpatterns项目开始时创建了一个空变量吗?是时候填充它了!

首先,让我们导入我们需要的所有视图和函数:

# photoapp/urls.py from django.urls import path from .views import ( PhotoListView, PhotoTagListView, PhotoDetailView, PhotoCreateView, PhotoUpdateView, PhotoDeleteView )

的路径函数接收两个参数,route以及view,和一个可选的参数,name,其被用作所述命名空间的一部分:

# photoapp/urls.py app_name = photo urlpatterns = [ path(, PhotoListView.as_view(), name=list), path(tag/<slug:tag>/, PhotoTagListView.as_view(), name=tag), path(photo/<int:pk>/, PhotoDetailView.as_view(), name=detail), path(photo/create/, PhotoCreateView.as_view(), name=create), path(photo/<int:pk>/update/, PhotoUpdateView.as_view(), name=update), path(photo/<int:pk>/delete/, PhotoDeleteView.as_view(), name=delete), ]

解释这个配置,app_name变量声明了应用程序的命名空间。

这意味着无论我们是reverse在视图中使用函数,还是{% url %}在模板中使用标签,我们都需要使用以下命名空间:

photo:<<url_name>>

如果您想了解有关 Django URL 调度程序如何工作的更多信息,请随时阅读文档。

认证系统

在这个项目中,我们将使用默认的Django 身份验证系统。

这是因为我们的主要重点是尽快拥有功能性应用程序。但是,我们将创建一个自定义应用程序,因为我们希望向项目添加注册功能。

首先,我们创建一个users应用程序并执行所有与我们相同的安装过程photoapp:

python manage.py startapp users # config/settings.py INSTALLED_APPS = [ ... # 3rd party apps taggit, # Custom apps photoapp, users, ]

接下来,我们urls.py像使用照片应用程序一样创建文件:

cd users/ touch urls.py

然后我们在整个项目中包含用户的 URL:

# config/urls.py urlpatterns = [ path(admin/, admin.site.urls), # Main app path(, include(photoapp.urls)), # Auth app path(users/, include(users.urls)), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

然后我们写一个SignUpView允许用户通过站点注册:

# users/views.py from django.views.generic import CreateView from django.contrib.auth import authenticate, login from django.contrib.auth.forms import UserCreationForm from django.urls import reverse_lazy class SignUpView(CreateView): template_name = users/signup.html form_class = UserCreationForm success_url = reverse_lazy(photo:list) def form_valid(self, form): to_return = super().form_valid(form) user = authenticate( username=form.cleaned_data["username"], password=form.cleaned_data["password1"], ) login(self.request, user) return to_return

这个视图是一个CreateView并与内置的UserCreationForm 一起工作来创建一个新用户。

form_valid在将用户重定向到照片仪表板之前,我们使用该方法登录用户。

我们将创建一个登录视图,因为我们想要使用自定义模板来显示登录页面。为此,我们将导入内置LoginView函数并从中继承:

# Previous imports from django.contrib.auth.views import LoginView class SignUpView(CreateView): ... class CustomLoginView(LoginView): template_name = users/login.html

最后,是时候创建 URL 路由了:

# users/urls.py from django.urls import path from django.contrib.auth.views import LogoutView from .views import SignUpView, CustomLoginView app_name = user urlpatterns = [ path(signup/, SignUpView.as_view(), name=signup), path(login/, CustomLoginView.as_view(), name=login), path(logout/, LogoutView.as_view(), name=logout), ]

再一次,我们正在使用app_name变量。所以用户应用程序的命名空间将是这样的:

user:<<url_name>>

我们正在设置三个 URL。该signup/和login/使用我们所创建的自定义视图,但logout/URL是使用Django的内置LogoutView。

在继续之前,让我们在config/settings.py文件中配置身份验证重定向:

# Other settings ... USE_TZ = True # Django Authentication LOGIN_URL = user:login LOGIN_REDIRECT_URL = photo:list LOGOUT_REDIRECT_URL = photo:list

这告诉 Django 登录 URL 是自定义用户登录 URL,并且当用户登录时,他们必须重定向到照片仪表板。

前端

在用 Django 构建后端(用户看不到的)之后,是时候构建前端(用户看到的)了。

为此,我们将使用Django 模板语言和Bootstrap 5。这允许我们动态生成 HTML 并根据数据库的状态生成不同的输出。通过使用模板继承,我们可以节省大量代码。使用 Bootstrap 5 意味着我们不会使用静态文件。

编写基本模板

在本节中,我们将构建base.html文件,该文件是所有其他文件都将继承的模板。

为此,我们必须更改位于设置文件中DIRS的TEMPLATES变量内的键:

# config/settings.py TEMPLATES = [ { # Options .. DIRS: [BASE_DIR / templates], APP_DIRS: True, # More options }, ]

Django 的默认行为是在templates/每个应用程序的文件夹中搜索模板文件。

例如,可以在 中找到照片共享应用程序的模板photoapp/templates。用户应用程序 ( users/templates) 也是如此。

通过将DIRS键分配给[BASE_DIR / templates],我们告诉 Django 也在名为 的文件夹中搜索模板templates。

templates在项目的根目录(manage.py文件所在的位置)创建一个目录并触摸base.html和navbar.html模板:

ls # manage.py mkdir templates && cd templates touch base.html navbar.html

总结我们项目的模板可以在这三个目录中的任何一个中找到:

. ├── photoapp │ └── templates │ └── photoapp ├── templates └── users └── templates └── users

请记住,您可以随时查看GitHub 存储库上的项目结构。

在base.html模板中,我们将设置基本的 HTML 结构、一些元标记、引导 CDN 的链接以及其他模板将使用的块:

<!-- templates/base.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>Django Photo Sharing app</title> <link href="" rel="stylesheet" integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0" crossorigin="anonymous" /> <link rel="stylesheet" href="" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous" /> </head> <body> {% include navbar.html %} <div class="container mt-4"> {% block body %} {% endblock body %} </div> <script src="" integrity="sha384-p34f1UUtsS3wqzfto5wAAmdvj+osOnFyQFpp4Ua3gs/ZV6oOypYoCJhGGScy+8" crossorigin="anonymous" ></script> </body> </html>

该{% include %}标签(顾名思义)包括内选定模板的所有代码base.html文件。

因此,存在于 中的所有代码navbar.html都将放置在正文的开头。

注意:这里有很多 HTML 和 Bootstrap。随意复制所有内容,因为这不是本教程的主要重点。

下面是导航栏的 HTML 模板代码。此导航栏将包含一些逻辑以显示登录页面的链接,以防用户未登录:

<!-- templates/navbar.html --> <nav class="navbar navbar-expand-md navbar-dark bg-dark"> <div class="container-fluid"> <a class="navbar-brand" href="{% url photo:list %}">Photo App</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarTogglerDemo02" aria-controls="navbarTogglerDemo02" aria-expanded="false" aria-label="Toggle navigation" > <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse flex-row-reverse" id="navbarTogglerDemo02" > <ul class="navbar-nav"> {% if user.is_authenticated %} <li class="nav-item"> <a class="nav-link active" href="{% url photo:create %}">Add a photo</a> </li> <li class="nav-item"> <a class="nav-link active" href="#">Hi {{user.username}}</a> </li> {% else %} <li class="nav-item"> <a href="{% url user:login %}" class="btn btn-sm btn-danger" >Sign In</a > </li> {% endif %} </ul> </div> </div> </nav>

以下是用户登录时模板的显示方式。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

以下是用户未登录时显示的内容。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

如果您的浏览器出现错误,请不要担心。我们还没有构建照片共享模板。

照片分享模板

我们将编写照片共享应用程序中所需的所有文件。这包括用于完成 CRUD 操作的模板。

所有这些模板都将扩展base.html模板并将位于photoapp/templates/photoapp目录中。

但在使用模板中的表单之前,我们将使用Django 脆皮表单来风格化我们的应用程序

pip install django-crispy-forms

再一次,crispy_forms是一个 Django 应用程序,我们需要将它包含在INSTALLED_APPS列表中:

# config/settings.py INSTALLED_APPS = [ ... # 3rd party apps taggit, crispy_forms, # Custom apps photoapp, users, ] # Indicates the frontend framework django crispy forms will use CRISPY_TEMPLATE_PACK = bootstrap4

我们使用 Bootstrap 4 的模板包,因为 Bootstrap 表单类在第 4 版和第 5 版之间兼容(在撰写本文时)。

您可能还记得我们在 上使用了以下模板名称photoapp/views.py:

photoapp/list.html photoapp/taglist.html photoapp/detail.html photoapp/create.html photoapp/update.html photoapp/delete.html

这意味着所有这些模板都将位于photoapp/templates/photoapp.

要创建此文件夹,请转到照片共享应用程序并创建一个目录templates/,然后在其中创建另一个名为 的文件夹photoapp/:

cd photoapp/ mkdir -p templates/photoapp/ cd templates/photoapp/

现在创建我们在视图上声明的所有模板:

touch list.html taglist.html detail.html create.html update.html delete.html 列出模板

该list.html会从继承base.html模板,因此所有的HTML结构将出现在源代码中:

<!-- photoapp/templates/photoapp/list.html --> {% extends base.html %} {% block body %} <div class="row"> {% for photo in photos %} <div class="col-lg-3 col-md-4 col-xs-6"> <a href="{% url photo:detail photo.id %}" class="d-block mb-4 h-100"> <img src="{{photo.image.url}}" class="img-fluid rounded" alt="{{photo.title}}" /> </a> </div> {% endfor %} </div> {% endblock body %}

我们使用模板标签for loop,它迭代照片并用 Bootstrap 行和列显示它们。

不要忘记在 Django 管理中创建多个照片对象。

访问localhost:8000/以查看模板的外观。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

该taglist.html模板将从继承list.html刚刚创建我们:

<!-- photoapp/templates/photoapp/taglist.html --> {% extends photoapp/list.html %} {% block body %} <div class="alert alert-primary"> <h2 class="text-center">Photos with the tag {{tag}}</h2> </div> {{ block.super }} {% endblock body %}

我们只是稍微修改了这个模板。这就是我们调用 的原因{{ block.super }},它包含list.html模板主体块中的所有代码。

code在继续之前创建几个带有标签的对象。

转到localhost:8000/tag/code/,其中代码是标签的 slug。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

请记住,该taglistURL 具有以下形式:

localhost://8000/tag/<slug:tag>/

这里,<slug:tag>指的是标签的名称。

细节照片模板

让我们编辑detail.html模板,以便能够详细查看我们的照片:

<!-- photoapp/templates/photoapp/detail.html --> {% extends base.html %} {% block body %} <div class="mx-auto"> <h1 class="text-center">{{ photo.title }}</h1> <p class="text-center fw-light">Uploaded on: {{photo.created}} <br> By {{photo.submitter.username}}</p> {% if user == photo.submitter %} <p class="text-center"> <span><a href="{% url photo:update photo.id %}" class="text-primary px-2">Update</a></span> <span><a href="{% url photo:delete photo.id %}" class="text-danger px-2">Delete</a></span> </p> {% endif %} </div> <div class="row pb-5"> <div class="col-md-8"> <img src="{{photo.image.url}}" alt="" width="100%" /> </div> <div class="col-md-4"> <h4>More about this photo:</h4> <ul class="list-group list-group-horizontal-lg list-unstyled py-4"> {% for tag in photo.tags.all %} <li><a href="{% url photo:tag tag.slug %}" class="btn btn-sm list-group-item list-group-item-primary">{{tag.name}}</a></li> {% endfor %} </ul> <p>{{ photo.description }}</p> </div> </div> {% endblock body %}

在深入研究功能之前,让我们看看模板的外观。按照localhost:8000/photo/1。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

在这里,我们通过点符号从模板访问照片属性。那是因为photo.submitter.username等于daniel。

我们实现了一些逻辑来显示更新或删除照片的链接,以防用户也是提交者。

最后,我们显示迭代的照片的所有标签photo.tags.all。

创建照片模板

下一个模板将包含一个清晰的表单,因此我们不必手动显示表单。Django 会为我们做到这一点:

<!-- photoapp/templates/photoapp/create.html --> {% extends base.html %} {% load crispy_forms_tags %} {% block body %} <div class="mx-auto"> <h1 class="mt-3 text-center">Add photo</h1> </div> <div class="form-group"> <form action="" method="post" enctype="multipart/form-data"> {% csrf_token %} {{ form|crispy }} <button type="submit" class="btn btn-success mb-3">Add Photo</button> </form> </div> {% endblock body %}

每次我们使用脆皮表单时,我们都需要加载带有{% load crispy_forms_tags %}.

包含 非常重要enctype="multipart/form-data",因为如果我们不包含,文件将不会被上传。这是对在 forms 中使用它的影响的一个很好的回应。

每个 Django 表单都必须包含一个{% csrf_token %}inside。您可以在“跨站点请求伪造保护”页面上了解有关此标签的更多信息。

请注意我们如何简单地使用{{form|crispy}}. 如果您知道 Linux 中的管道是什么,我们正是通过将视图提供的表单重定向到crispy过滤器来做到这一点的。

转到添加照片URL 以检查照片是否已上传。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

如果一切顺利,我们应该会在仪表板中看到添加的照片。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

更新和删除模板

在前往身份验证模板之前,让我们完成照片共享应用程序

下面的update模板是一个简单的形式,其中用户可以更新title,description和tags照片的:

<!-- photoapp/templates/photoapp/update.html --> {% extends base.html %} {% load crispy_forms_tags %} {% block body %} <div class="mx-auto"> <h1 class="mt-3 text-center">Edit photo {{photo}}</h1> </div> <div class="form-group"> <form action="" method="post" enctype="multipart/form-data"> {% csrf_token %} {{ form|crispy }} <button type="submit" class="btn btn-success mb-3">Edit Photo</button> </form> </div> {% endblock body %}

我们可以看看它在localhost:8000/photo/1/update 上的样子。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

我们还希望为用户提供删除照片的选项。使用以下模板,他们可以决定是否删除照片:

<!-- photoapp/templates/photoapp/delete.html --> {% extends base.html %} {% block body %} <div class="form-group mx-auto"> <h2 class="text-center"> You are going to <span class="text-danger">delete</span>: "<i >{{ photo }}</i > " </h2> <p class="text-center">Are you sure, you want to delete the photo ?</p> <div class="form-group"> <form action="" method="post" class="d-flex flex-column align-items-center justify-content-center" > {% csrf_token %} <div class="row"> <div class="col"> <a href="{% url photo:detail photo.id %}" class="btn btn-primary" >Cancel</a > </div> <div class="col"> <button type="submit" class="btn btn-danger">Delete</button> </div> </div> <p>This action is irreversible</p> </form> </div> </div> {% endblock body %}

删除页面将如下所示。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

如果用户决定取消,他们将被重定向到该照片的详细信息页面。

用户认证模板

本节的目的是编写与身份验证相关的所有模板。我们将编写signup.html和login.html模板。

与照片共享应用程序类似,以下所有模板都将位于双文件夹结构中:users/templates/users/.

进入用户应用程序并创建模板所在的文件夹:

# Enter to the project root directory cd ../../../ cd users/ mkdir -p templates/users/

在该文件夹中创建注册和登录模板文件:

cd templates/users/ touch signup.html login.html

下面是模板的模板代码signup.html:

<!-- users/templates/users/signup.html --> {% extends base.html %} {% load crispy_forms_tags %} {% block body %} <div class="mx-auto"> <div class="form-group"> <form action="" method="post"> {% csrf_token %} {{ form|crispy }} <button type="submit" class="btn btn-danger w-100 my-3">Create account</button> </form> </div> {% comment %} Already Registered {% endcomment %} <div class="text-center w-100"> <p class="text-muted font-weight-bold"> Already Registered? <a href="{% url user:login %}" class="text-primary ml-2"> Login </a> </p> </div> </div> {% endblock body %}

我们可以在浏览器中查看localhost:8000/users/signup。

 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

最后但并非最不重要的是,编写登录模板:

<!-- users/templates/users/login.html --> {% extends base.html %} {% load crispy_forms_tags %} {% block body %} <div class="mx-auto"> <div class="form-group"> <form action="" method="post"> {% csrf_token %} {{ form|crispy }} <button type="submit" class="btn btn-danger w-100 my-3">Sign in</button> </form> </div> {% comment %} Already Registered {% endcomment %} <div class="text-center w-100"> <p class="text-muted font-weight-bold"> Dont have an account? <a href="{% url user:signup %}" class="text-primary ml-2">Create account</a> </p> </div> </div> {% endblock body %}  用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态 用Django构建一个照片共享应用程序19图 小程序动态

Django 模板允许我们通过多次重用相同的 HTML 来节省大量时间。只需想象一遍又一遍地复制和粘贴相同的 HTML 会花费多少时间。

完美的!现在你有一个完全可用的应用程序。尝试使用它、修改它,甚至扩展它的功能。

加起来

恭喜!您已经从头开始创建了一个全栈项目。

Django 是最常用的 Python Web 框架。它允许您快速构建复杂的 Web 应用程序。

它具有许多可加速开发过程的内置功能,例如服务器端模板渲染、基于类的视图和模型表单。

Django 还提供了几个第三方包,让您可以选择使用其他人的应用程序。例如,该项目使用 Django taggit 和 Django 脆皮形式。

在本教程中,我们介绍了以下内容:

Django CRUD 操作Django 内置身份验证系统如何在 Django 中管理媒体文件使用 Django taggit 对内容进行分类用脆皮形式实现 Django 表单使用 Bootstrap 5 编写 Django 模板

最好的方法是不断学习和推进它,将您获得的知识应用到新的和具有挑战性的项目中。祝你好运!

相关文章

网友留言

发表评论

◎欢迎参与讨论