使用 Django 构建社交网络 - 第 1 部分
目录
在这个由四部分组成的教程系列中,您将使用 Django 构建一个可以在您的作品集中展示的社交网络。该项目将加强您对 Django 模型之间关系的理解,并向您展示如何使用表单,以便用户可以与您的应用程序以及彼此进行交互。您还将学习如何使用 Bulma CSS 框架使您的网站看起来不错。
在本教程系列的第一部分中,您将学习如何:
- 实现Django模型之间的一对一和多对多关系
- 使用自定义模型扩展 Django用户模型
Profile
- 自定义Django 管理界面
完成本系列的第一部分后,您将进入第二部分,您将在其中学习集成Bulma来为您的应用设置样式并实现前端界面和逻辑,以便您的用户可以相互关注和取消关注.
您可以通过单击下面的链接并转到文件夹来下载该项目第一部分的代码source_code_final/
:
项目概况
在本节中,您将对要构建什么以及为什么要以这种方式构建它有一个坚实的概念。您还将深入研究您将实施的数据库关系,并且您将提出一个完整的项目大纲,准备就绪。简而言之,您将留出一些时间来集思广益您的项目想法。
制定计划后,您将开始本系列第一部分的实际实施步骤,该部分侧重于 Django 模型及其关系:
要深入了解如何通过本系列的所有四个部分来构建 Django 社交网络,您可以展开下面的可折叠部分:
您将通过分布在四个部分的一系列步骤来实施该项目。有很多内容需要介绍,您将在此过程中详细介绍:
- 第 1 步:设置基础项目
- 第 2 步:扩展 Django 用户模型
- 第 3 步:实施保存后挂钩
- 第 4 步:使用 Bulma 创建基本模板
- 第 5 步:列出所有用户配置文件
- 第 6 步:访问个人资料页面
- 第 7 步:关注和取消关注其他个人资料
- 第 8 步:为 Dweets 创建后端逻辑
- 第 9 步:在前端显示 Dweets
- 第 10 步:通过 Django 表单提交 Dweets
- 第 11 步:防止重复提交并处理错误
- 第 12 步:改善前端用户体验
这些步骤中的每一个都将提供指向任何必要资源的链接,并让您有机会暂停并稍后再回来,以防您想休息一下。
您可能渴望开始编程,但在开始从事任何编码项目之前,考虑一下您想要构建的结构会有所帮助。
您可以使用伪代码、书面规范、数据库图表、笔记本涂鸦或任何感觉可以访问并帮助您思考的东西。不要跳过这部分!这是构建任何项目的重要步骤。您在规划上投入的时间将大大减少您的实施时间。
那么,社交网络需要什么?在最基本的形式中,您需要两件事:
- 允许人们相互联系的用户对用户连接
- 内容创建和显示功能,以便您的用户可以为其连接的用户创建输出以查看
您可以将这两个主题视为彼此独立的主题,但您的社交网络需要它们两者才能按预期运行。
用户到用户连接的配置文件
对于本教程系列的第一部分,您需要规划如何允许用户连接以及如何将其转换为数据库模式。这部分侧重于连接。
如何在 Django 模型中实现连接?首先,您将记下这些连接的基本版本可能是什么样子:
- 您的社交网络中将有多个用户。
- 他们需要相互了解,以便他们可以决定要跟随谁。
对于这个项目,您将根据扩展上述两个基石的几个假设来实现社交网络用户之间的连接:
- 您的用户将能够关注或不关注其他用户。
- 如果他们关注某人,他们将看到该用户的内容。如果他们不这样做,他们就不会。
- 您的用户可以关注一个人而不会被关注。您的社交网络中的关系可能是不对称的,这意味着用户可以关注某人并查看他们的内容,而反之亦然。
- 您的用户需要知道谁存在,以便他们知道可以关注谁。
- 用户还应该知道谁在关注他们。
- 在您的应用程序最基本的形式中,用户不会有很多额外的功能可供他们使用。您不会实施阻止人们的方法,也不会有直接响应其他人发布的内容的方法。
从本质上讲,您可以将您的社交网络视为用户可以订阅或不订阅的简短博客或 RSS 提要的存储库。这是您将在这个由四部分组成的系列中构建的实现。稍后,您可以在此基础上构建,使您的社交网络更加具体和复杂。
通过将 Django 的内置模型与扩展此默认模型User
的自定义模型相结合,您将获得所需的功能:Profile
User
在上图中,您可以看到实体关系 (ER) 图的草稿,显示每个用户都将拥有一个完整的个人资料,并且这些个人资料可以不对称地相互跟随。
该图并不旨在完美或完整。对于您自己的过程,也许您会想在一张纸上勾勒出一些稍微不同的东西。您正在集思广益,因此请使用最适合您的格式。
基于文本的内容
除了建立用户之间的关系外,您的平台还需要一种用户创建和共享内容的方式。内容可以是任何东西。它可以包括图像、文本、视频、网络漫画等。
在此项目中,您将构建一个社交网络,用于处理基于有限字符文本的消息,类似于Twitter。因为您将使用 Django Web 框架来制作它,所以它将带有流行的名称Dwitter。
您的 Dwitter 网络将需要一个模型来存储用户可以创建的基于文本的消息,您将其称为dweets。您将只记录有关每个 dweet 的三条信息:
- 谁写的
- 消息说什么
- 当用户写它时
您只需要为Dweet
模型定义一种关系,即它与内置User
模型的连接:
ER 图显示了内置User表如何通过一对多关系连接到Dweet表。这种类型的关系意味着一个用户可以拥有许多 dweets,并且每个 dweet 只属于一个用户。
您还可以在表中查看与您要收集的有关每个 dweet 的信息相对应的不同字段:
user
:保存有关谁写了消息的信息body
:保存消息的文本内容created_at
:保存用户发布消息的日期和时间
该created_at
字段在 ER 图中显示为灰色,因为您不允许您的用户自己编辑它。相反,每当用户提交新消息时,Django 都会自动填写该字段。
注意:您起草的模型都没有很多字段,这是一件好事!您想要创建一个满足您之前头脑风暴的标准的基本社交网络实现。以后你总是可以让它变得更复杂。
您还需要一种方法让您的用户创建内容并查看他们和他们网络中的其他人创建的内容。为了方便您的用户,您必须执行以下一些任务来设置前端:
- 提供用于提交内容的表单
- 创建视图来处理这些提交
- 构建模板以显示现有内容
- 让它看起来体面
您将在本系列中介绍的大多数主题都是适用于许多 Django Web 应用程序的一般主题。您可能已经知道如何做其中的一些,但在这里您将在一个全新项目的背景下探索它们。即使您还没有遇到任何涉及的任务,您也将学习如何一个接一个地应对每个挑战。
现在您已经花了一些时间来集思广益您的项目想法,您可以准备好构建它!
先决条件
要完成本教程系列,您应该熟悉以下概念:
- 在 Python 中使用面向对象编程
- 设置一个基本的 Django 项目
- 在 Django 中管理路由和重定向、查看函数、模板、模型和迁移
- 使用和自定义 Django 管理界面
- 使用类属性读写 HTML
如果您在开始本教程之前没有所有这些知识,没关系!您可能会通过继续前进并开始了解更多信息。如果遇到困难,您可以随时停止并查看上面链接的资源。
因为您将使用 Django 为您的社交网络构建后端,所以您需要熟悉 Django 框架以充分利用本系列。如果您以前没有经常使用 Django,您可能想尝试构建一个首先关注基础知识的 Django 项目。为了获得良好的介绍,您可以通过构建一个投资组合应用程序来了解 Django。
第 1 步:设置基础项目
此时,您知道您将构建什么并且您了解您将实现的数据库关系。在这一步结束时,您将设置一个 Django 项目并编辑 Django 管理界面以允许创建集中且简约的用户。
您将依次处理几个步骤:
- 创建虚拟环境并安装Django
- 创建一个 Django项目和应用程序
- 自定义 Django管理界面
- 为您的应用创建用户
在做任何其他事情之前,您将首先创建一个虚拟环境并安装 Django。
创建虚拟环境并安装 Django
首先创建一个新的项目根文件夹,您将在其中放置您在处理此项目时制作的所有文件,然后导航到该文件夹:
$ mkdir django-social
$ cd django-social
导航到您将开发项目的父文件夹后,您可以创建并激活虚拟环境并从Python Packaging Index (PyPI)安装 Django :
$ python3 -m venv venv --prompt=social
$ source ./venv/bin/activate
(social) $ python -m pip install django==3.2.5
这些命令会创建一个名为 的新虚拟环境social
,激活此环境并安装 Django。
创建一个 Django 项目和应用程序
安装完成后,您可以启动一个名为social
. 您的项目名称不必与您的虚拟环境的名称保持一致,但这样一来,它会更容易记住。
创建 Django 项目后,创建一个新的 Django 应用程序,调用dwitter
它来配合它:
(social) $ django-admin startproject social .
(social) $ python manage.py startapp dwitter
您还需要将新dwitter
应用注册INSTALLED_APPS
到social/settings.py
:
# social/settings.py
# ...
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"dwitter",
]
将您的应用程序的名称添加到此列表将使 Django 知道您希望将该应用程序包含在您的 Django 项目中。此步骤是必要的,以便您所做的编辑dwitter
会影响您的项目。
注意:如果您需要更详细的说明来帮助您进行设置,您可以了解如何设置 Django。
在继续学习本教程之前,请确保您拥有:
- 激活的虚拟环境
- 一个名为的新 Django 项目
social
- 一个名为的 Django 应用程序
dwitter
- 注册为应用的项目
settings.py
文件dwitter
如果您卡在这些步骤中的任何一个上,那么您将在上面链接的关于如何设置 Django 的专用教程中找到详细描述的所有必要设置步骤。
自定义 Django 管理界面
Django 的内置管理界面是管理应用程序的强大工具,您将在本教程中使用它来处理用户创建和管理。
注意:您不会在本教程中实现任何面向用户的注册功能。但是,您可以稍后按照Django 用户管理教程添加此功能。
为了让您的管理界面体验专注于基本要素,您将应用一些自定义。在此之前,您将查看默认状态。您需要设置 Django 的默认 SQLite 数据库并创建一个超级用户,以便您可以登录到 Django 管理门户:
(social) $ python manage.py migrate
(social) $ python manage.py createsuperuser
Username: admin
Email address: admin@example.com
Password:
Password (again):
运行这两个命令并输入超级用户帐户的信息后,您可以启动 Django 的开发服务器:
(social) $ python manage.py runserver
导航到/admin
localhost 上端口 8000 的 URL 并登录到管理门户:
您可以看到Groups和Users的默认模型条目。这些来自 Django 的内置身份验证和用户管理应用程序。如果您还不熟悉它们,请随意环顾四周。
里面有很多!但是,您希望使该项目尽可能接近基础,以关注模型关系和社交网络的内容。
为了简化您的管理员,您可以减少一些事情:
- 您不会使用 Django 的Groups,因此您可以将它从您的管理视图中完全删除。
- 在 Django 中创建用户的最基本方法是只传递一个用户名。您也可以从用户模型显示中删除所有其他字段。
首先注销Group
模型,这会从您的管理界面中删除该模型:
# dwitter/admin.py
from django.contrib import admin
from django.contrib.auth.models import Group
admin.site.unregister(Group)
要取消注册Group
,首先将其从django.contrib.auth.models
. 然后,使用.unregister()
将其从您的管理显示中删除。
探索:Django 管理界面显示隐藏
接下来,您将更改 Django 内置User
模型的管理部分中显示的字段。为此,您需要先取消注册它,因为该模型默认已注册。然后,您可以重新注册默认User
模型以限制 Django 管理员应显示的字段。为此,您将使用自定义UserAdmin
类:
1# dwitter/admin.py
2
3from django.contrib import admin
4from django.contrib.auth.models import User, Group
5
6class UserAdmin(admin.ModelAdmin):
7 model = User
8 # Only display the "username" field
9 fields = ["username"]
10
11admin.site.unregister(User)
12admin.site.register(User, UserAdmin)
13admin.site.unregister(Group)
将此代码添加到您的admin.py
文件可以简化管理站点中显示的内容User
,以及创建新用户时需要输入的信息。回顾一下,这是您在不同代码行中所做的事情:
-
第 4 行:添加另一个导入,从中获取内置
User
模型django.contrib.auth.models
。 -
第 6 到 9 行:创建
UserAdmin
一个基于导入User
模型的自定义类。 -
第 9 行:您将管理界面显示的字段限制为仅
username
,这足以创建一个测试用户。 -
第 11 行:
User
取消注册默认在管理界面中注册的模型。 -
第 12 行:您再次注册
User
模型,另外传递UserAdmin
您创建的自定义类,该类应用您想要的更改。
如果您现在导航到Home → Authentication and Authorization → Users中的用户概述页面,那么您会注意到您的管理门户显示的信息比以前少得多:
通过设置 Django 管理界面的这些自定义设置,您现在可以通过仅提供用户名来快速为您的应用程序创建测试用户。
为您的应用创建用户
通过单击界面右上角的添加用户按钮导航到主页 → 身份验证和授权 → 用户 → 添加用户。单击此按钮将带您进入默认的 Django 用户模型的用户创建表单:
这个简化的管理门户允许您在需要时为您的 Django 社交网络快速创建额外的测试用户,您只需要为他们提供一个用户名。
注意:仅将这些用户帐户用于开发目的。在不定义密码或任何其他信息的情况下设置用户是不安全的。
继续并通过此界面创建两个额外的用户。你可以给他们任何你喜欢的名字,比如alice和bob。设置额外用户后,您就完成了项目的初始设置。
至此,您已经完成了一些重要的事情:
- 您创建了一个名为
social
. - 您创建了一个名为
dwitter
. - 您清理了管理门户以专注于您需要的基本功能。
- 您为您的社交网络创建了一些用户。
现在是时候考虑要在社交网络中实现的功能了。如果您调查刚刚创建的 Django 用户,您可能会注意到内置User
模型没有任何允许用户连接的功能。要对用户之间的连接进行建模,您需要扩展默认的 DjangoUser
模型。
第 2 步:扩展 Django 用户模型
至此,您拥有一个功能齐全的 Django 项目,其中包含几个注册用户。在这一步结束时,您将拥有一个链接到内置 DjangoUser
模型的每个用户的配置文件,从而允许用户进行连接。
您需要一种方法来保存有关您的应用程序用户的信息。如果您从头开始,则必须为此构建一个全新的用户模型。相反,您将使用内置的 DjangoUser
模型来依赖 Django 经过充分测试的实现,这样您就可以避免重新发明身份验证轮。
但是,您还需要默认User
模型未涵盖的附加功能:一个用户如何关注另一个用户?您需要一种将用户与其他用户联系起来的方法。
虽然 Django 中的内置User
模型很有帮助,但在构建自定义应用程序时通常还不够,因为它专注于身份验证所需的最低设置。继续利用 Django 的内置用户管理功能,同时添加您的特定自定义项的一个好方法是扩展User
模型。
注意:在一般编程术语中,您会看到在谈论继承时使用的术语扩展。不过在Django社区中扩展模型也可以参考其他不涉及继承的自定义内置模型的方式。User
User
在本教程中,您将使用一对一的关系链接两个单独的模型,这是官方建议的应对这一挑战的方法之一。
创建Profile
模型
User
您将通过使用一对一的关系与一个小而专注的新模型来扩展 Django 的内置模型, Profile
. 您将Profile
从头开始构建它。此Profile
模型将跟踪您要收集的有关每个用户的附加信息。
User
除了 Django模型已经包含的用户信息之外,您还需要什么?在寻找可能的解决方案之前,拿出您的笔记本并集思广益,了解您的基本社交网络所需的其他用户属性:
解决方案:你需要什么?显示隐藏
您可以添加比上述内容更多的关于每个用户的详细信息,例如传记信息。完成本教程系列后,向Profile
模型添加更多细节将是一个很好的练习。
该Profile
模型仅包含您的用户在他们已经拥有用户帐户后创建的信息,这允许您让 Django 处理注册和身份验证过程。这是扩展现有User
模型的建议方法之一,因此您会坚持使用它。
您的Profile
模型应该记录用户与其他用户配置文件的连接。这是在成功建模用户到用户连接之前仍然缺少的基本信息。这意味着您对Profile
模型的主要关注点将是设置它以记录谁关注了个人资料,以及从另一个方向记录个人资料关注的人。
您只需创建一个字段即可对这两种连接进行建模。这是因为 Django 可以将执行以下操作的配置文件视为与所遵循的配置文件具有反比关系:
ER 图显示Profile模型通过以下多对多关系连接到自身。
models.py
在您的应用中打开并为您的新模型dwitter
编写代码:Profile
1# dwitter/models.py
2
3from django.db import models
4from django.contrib.auth.models import User
5
6class Profile(models.Model):
7 user = models.OneToOneField(User, on_delete=models.CASCADE)
8 follows = models.ManyToManyField(
9 "self",
10 related_name="followed_by",
11 symmetrical=False,
12 blank=True
13 )
通过这种方式设置Profile
,您可以将每个配置文件精确地耦合到一个用户:
-
第 4 行:
User
您导入要扩展的内置模型。 -
第 7 行:定义一个
OneToOneField
名为 的对象user
,表示配置文件与使用 Django 内置用户管理应用程序创建的用户的连接。您还定义了如果关联用户被删除,任何配置文件都将被删除。 -
第 8 到 13 行:
ManyToManyField
您使用字段 name定义一个对象,该对象follows
可以保持与其他用户配置文件的连接。 -
第 10 行:
related_name
在这一行中,您为字段中的关键字传递了一个值follows
,它允许您通过描述性名称从该关系的另一端访问数据条目"followed_by"
。 -
第 11 行:您还设置
symmetrical
为,False
以便您的用户可以关注某人而无需他们跟进。 -
第 12 行:最后,您设置
blank=True
,这意味着您的用户不需要关注任何人。该follows
字段可以保持为空。
通过Profile
设置,您可以运行 Django 的数据库命令将模型更新传播到您的数据库:
(social) $ python manage.py makemigrations
(social) $ python manage.py migrate
运行makemigrations
会创建一个迁移文件,该文件将更改注册到数据库,并将migrate
更改应用到数据库。
您现在可以将Profile
模型注册到您的管理界面,以便管理员在内置User
模型之外显示它:
# dwitter/admin.py
# ...
from .models import Profile
# ...
admin.site.register(Profile)
从您当前的应用程序导入Profile
并使用管理界面注册后,您可以重新启动开发服务器:
(social) $ python manage.py runserver
运行后,转到您的管理界面。配置文件显示在DWITTER面板中的User
模型下方:
如果您单击Profiles旁边的+ Add,Django 将为您提供一个视图:profile create
您需要选择要与配置文件关联的用户。从下拉列表中选择用户后,您可以单击“保存”来创建您的第一个用户配置文件。之后,配置文件将显示为Follows内的可选对象:
您可以选择新的配置文件对象配置文件对象 (1)并再次单击保存以关注您自己的用户配置文件。
此时,您已经拥有创建配置文件和关注其他配置文件所需的所有功能。然而,当它们如此紧密地连接且信息量极少时,在两个不同的地方展示User
和显示可能看起来不方便。Profile
通过对管理界面进行更多自定义,您可以改进此设置。
在用户管理页面中显示配置文件信息
在本教程系列中,您将通过管理员处理用户创建。您的每个用户都需要一个用户帐户和一个配置文件,并且这两个需要连接。
您无需在两个不同的地方创建用户及其个人资料,而是通过添加admin inline来自定义您的管理界面,这样您就可以在一个区域中同时编辑两者。
返回以dwitter/admin.py
将您的新Profile
模型注册为堆叠内联,而不是注册模型的标准方式。您可以使用UserAdmin
之前创建的类并通过将相关模型添加为内联来对其进行自定义:
# dwitter/admin.py
# ...
class ProfileInline(admin.StackedInline):
model = Profile
class UserAdmin(admin.ModelAdmin):
model = User
fields = ["username"]
inlines = [ProfileInline]
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
admin.site.unregister(Group)
# Remove: admin.site.register(Profile)
在此代码片段中,您Profile
通过创建ProfileInline
和继承自admin.StackedInline
. 然后,您可以将其添加ProfileInline
为inlines
您的UserAdmin
.
注意: inlines
是一个可以包含多个条目的列表,但在这种情况下,您只想添加一个。
最后,您还删除了之前Profile
单独注册模型的最后一行。
当您进入管理界面时,您会看到个人资料条目已从主页中消失。但是,当您通过“用户”页面导航到一个用户条目时,您会在用户信息旁边看到个人资料信息:
从Profile
现在开始的信息与来自 Django 内置模型的信息一起User
显示,您将其限制为仅显示用户名字段。
这是一项重大改进,使通过管理界面处理用户更加方便!
但是,您的个人资料名称目前难以解释。您怎么知道Profile 对象 (1)是admin的用户配置文件?如果没有与您的Profile
模型相关的描述性信息,这很难猜到。要改变这一点,请返回dwitter/models.py
并添加一个.__str__()
方法Profile
:
# dwitter/models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
follows = models.ManyToManyField(
"self", related_name="followed_by", symmetrical=False, blank=True
)
def __str__(self):
return self.user.username
通过此添加,您重载了默认.__str__()
方法,以便它username
从模型的关联实例返回值User
。通过重新加载页面检查管理界面中的结果:
在此更改之后,连接到管理员用户的配置文件对象会在关注列表中显示该用户的名称。
但是,到目前为止,您创建的其他用户都没有个人资料。最终,您会希望每个用户都有一个配置文件,其中包含与该用户相关的附加信息。
练习:创建和关联配置文件显示隐藏
您可以通过在管理界面中创建一个新的配置文件并通过您的管理内联将其与用户帐户关联来尝试您的模型设置。
在您创建更多具有关联配置文件的用户后,您会看到他们填充了关注列表。您可以选择此列表中显示的一个或多个配置文件。单击“保存”后,该配置文件将开始关注它们。
你能想出如何改进这个过程的想法吗?
由于您希望每个用户始终拥有一个与之关联的个人资料,因此您可以设置 Django 来为您完成这项任务。每次创建新用户时,Django 也应该自动创建合适的用户配置文件。此外,它应该立即与该用户相关联。您可以models.py
通过使用信号来实现这一点。
第 3 步:实施保存后挂钩
您现在拥有用户和配置文件,以及一种通过管理界面创建和关联它们的方法。在此步骤结束时,您将连接它们,以便创建新用户将自动创建新配置文件并将一个与另一个相关联。在这一步中,您还将练习解释 Django 的错误消息,并通过错误驱动的开发找到调查和解决挑战的方法。
使用信号协调用户和配置文件
您已扩展内置User
模型,但尚未在用户和配置文件之间创建自动连接。到目前为止,您只能通过管理界面手动创建用户和配置文件并将配置文件与用户关联。
探索:手动关联用户和配置文件显示隐藏
如果您还没有尝试手动执行此操作,请立即尝试。在 Django 管理员中创建一个新配置文件,然后将其与现有用户帐户相关联。
在创建用户时自动将新的个人资料与用户相关联会非常好,不是吗?您可以使用Django 信号来实现这一点。回到你的dwitter/models.py
文件。
注意: Django 文档提到放置信号的最佳位置是在signals.py
应用程序的新子模块中。但是,这需要您在应用配置中进行其他更改。由于您只需要为本教程构建一个信号,因此您将其保留在models.py
.
您已经制定了要实现的目标:在数据库中创建新用户时,您还希望创建新配置文件并将其链接到该用户。
您可以在 的帮助下实现此功能,post_save
每次create_profile
您的代码执行用户模型的.save()
. 请注意,这是您在外部定义的create_profile()
顶级函数:Profile
1# dwitter/models.py
2
3from django.db.models.signals import post_save
4
5# ...
6
7def create_profile(sender, instance, created, **kwargs):
8 if created:
9 user_profile = Profile(user=instance)
10 user_profile.save()
11
12# Create a Profile for each new user.
13post_save.connect(create_profile, sender=User)
您已向models.py
文件中添加了额外的代码行:
-
第 3 行:首先导入
post_save
. -
第 7 到 10 行:您编写了一个名为的新函数,
create_profile
它使用来决定是否创建新实例。只有当 post-save 信号表明 Django 成功创建了用户对象时,您的代码才会继续。created
post_save
Profile
-
第 9 行:
User
由于您在和之间建立了一对一的连接Profile
,您需要将一个User
对象传递给Profile
构造函数。你可以通过instance
作为参数传递给Profile
. -
第 10 行:在这里,您将新配置文件提交到您的数据库
.save()
。 -
第 13 行:您将保存后信号设置为在模型
create_profile()
每次执行时执行。您可以通过将关键字参数传递给.User
.save()
User
sender
这种保存后信号的实现为每个新用户创建了一个新的配置文件。通过将新创建的用户传递给Profile
构造函数,您可以自动将一个与另一个关联起来。
注意:当触发保存后信号时,它会返回多个变量,因此您可以**kwargs
在create_profile()
.
您可以在这里为每个新用户提供一个干净而空旷的个人资料来结束它。但是,您会自动将用户自己的个人资料添加到他们关注的个人资料列表中,因此每个用户还将看到他们自己编写的 dweets。
当您冒险学习新事物时,您可能会左右遇到错误。在下一节中,您将练习面对错误消息时的冷静,并了解当您不可避免地发现自己与 Django 沟通不畅时,如何继续朝着正确的方向前进。
通过错误驱动的开发添加功能
如果您完全按照在上一节中构建它的方式使用保存后信号,那么当您实际在稍后设置的仪表板上时,您将看不到任何 dweets 。但是,由于回忆自己的个人想法和帖子会很有趣,因此您将更改代码,以便用户在创建个人资料时默认自动关注自己。
当您尝试按照分步教程之外的方式做自己的事情时,通常很难在第一次获得正确的代码。同时,学习如何继续前进并找到解决方案至关重要!因此,您将在开发此功能时练习遇到错误,并了解如何解决这些挑战。
注意:如果您已经习惯于按照错误消息开发代码,或者您之前已经使用过 Django 信号,那么请随意跳过本节并继续重构您的代码以使用装饰器。
因为您希望在创建个人资料后立即关注您的个人资料,所以请回想一下follows
. Profile
也许您可以在创建实例时instance
通过关键字添加 post-save 钩子函数:follows
Profile
def create_profile(sender, instance, created, **kwargs):
if created:
user_profile = Profile(user=instance, follows=[instance])
user_profile.save()
这似乎很快!启动您的开发服务器并创建一个新用户以检查它是否按预期工作。
嗯,不完全是。您最终会遇到一条错误消息:
Direct assignment to the forward side of a many-to-many set is prohibited.
Use follows.set() instead.
Django 不知道如何处理你的指令,但它试图猜测然后给你一个建议。如错误消息所示,follows=[instance]
从中删除Profile
并尝试改用:follows.set()
def create_profile(sender, instance, created, **kwargs):
if created:
user_profile = Profile(user=instance)
user_profile.follows.set(instance)
user_profile.save()
通过在您的 Django 管理员中创建另一个新用户来冲洗并重复您的手动测试。Django 仍然对您的代码不完全满意,但它理解得更多,这意味着它会给您一个不同的错误消息:
ValueError at /admin/auth/user/add/
"<Profile: name>" needs to have a value for field "id" before this
many-to-many relationship can be used.
您可能还记得,您需要先提交您的对象,.save()
然后它们才能在您的数据库中有条目。当 Django 创建数据库条目时,它也会自动id
在条目中创建字段。
在此错误消息中,Django 告诉User
您数据库中首先需要存在一个实例,以便您可以使用.set()
将实例添加到follows
. 这是一个可行的提示!也许您可以先将新配置文件保存到数据库中,然后将其添加到follows
并再次保存:
def create_profile(sender, instance, created, **kwargs):
if created:
user_profile = Profile(user=instance)
user_profile.save()
user_profile.follows.set(instance)
user_profile.save()
当您创建一个新用户时,您这次寄予厚望!然而,Django 再次感到困惑:
TypeError at /admin/auth/user/add/
'User' object is not iterable
错误消息看起来好像 Django 正在尝试迭代instance
,它指的是新创建的User
对象。那是什么.set()
?是时候查看 Django 关于多对多关系的文档了:
可以设置关系集:
>>>>>> a4.publications.all() <QuerySet [<Publication: Science News>]> >>> a4.publications.set([p3]) >>> a4.publications.all() <QuerySet [<Publication: Science Weekly>]>
似乎.set()
真的需要一个可迭代的输入,Django 试图在错误消息中告诉你。因此,您可以将列表instance
作为单个项目传递,就像 Django 文档告诉您的那样:
def create_profile(sender, instance, created, **kwargs):
if created:
user_profile = Profile(user=instance)
user_profile.save()
user_profile.follows.set([instance])
user_profile.save()
此更改应允许.set()
遍历您传递的列表,并将与您的新用户帐户关联的配置文件添加到用户关注的帐户列表中。手指交叉,您再次尝试创建新用户,但出现另一个错误:
TypeError at /admin/auth/user/add/
TypeError: Field 'id' expected a number but got <User: name>.
那太棒了!您的错误消息会不断变化,从而为您提供更多信息。你在正确的道路上。
现在 Django 告诉你它得到了一个User
对象,但期望的是一个id
字段。您设置配置文件以跟随其他配置文件,但 Django 只寻找Profile
对象的.id
. 扩展User
模型后,您可以通过用户实例访问用户的个人资料.profile
,然后深入到对象中以获得.id
:
def create_profile(sender, instance, created, **kwargs):
if created:
user_profile = Profile(user=instance)
user_profile.save()
user_profile.follows.set([instance.profile.id])
user_profile.save()
是时候再旋转一次了。您使用管理界面创建一个新用户——例如,martin——现在它可以工作了:
恭喜!您设置了保存后挂钩,以便新创建的用户自动关注他们自己的个人资料。同样的保存后挂钩也自动创建了配置文件。
在制作此功能时,您还练习了在面对重复的错误消息时保持冷静。当误解发生时,您提高了对 Django 如何与您沟通的理解。
练习:替代实施显示隐藏
您可以按照建议的方式使用.add()
而不是.set()
. 搜索多对多关系文档并重构您的代码,使其使用.add()
.
解决方案:替代实施显示隐藏
您可以重构代码以使用.add()
而不是.set()
,这是添加单个实例的推荐方法:
def create_profile(sender, instance, created, **kwargs):
if created:
user_profile = Profile(user=instance)
user_profile.save()
user_profile.follows.add(instance.profile)
user_profile.save()
您可能还注意到,您不需要传递.id
链接Profile
对象,而是可以传递整个对象。这也适用于之前的解决方案,但是对于那个你遵循 Django 的错误消息的解决方案,它指出你应该使用.id
.
所有这些解决方案都有效!请记住,解决编程任务的方法总是不止一种。让它工作是最重要的,但最好的做法是按照最佳实践重新访问和重构您的代码。
在这种情况下,因为您总是只向集合中添加一个实例,所以您不需要迭代。这意味着使用它.add()
而不是.set()
. 另外,由于它具有相同的效果并且更具描述性,因此您可以instance.profile
直接传递而不是使用.id
.
通过此更改,您解决了用户在仪表板上看不到自己的 dweets 的问题。现在,他们的 dweets 将与他们关注的其他所有人一起出现。
此时,您可以保留此代码,但 Django 还提供了一种更优雅的方式来使用装饰器注册信号。在下一节中,您将使用receiver
.
使用装饰器重构代码
Django 带有一个receiver
装饰器,它允许您使您编写的代码更简洁,而无需更改其功能:
1# dwitter/models.py
2
3from django.db.models.signals import post_save
4from django.dispatch import receiver
5
6# ...
7
8@receiver(post_save, sender=User)
9def create_profile(sender, instance, created, **kwargs):
10 if created:
11 user_profile = Profile(user=instance)
12 user_profile.save()
13 user_profile.follows.add(instance.profile)
14 user_profile.save()
15
16# Remove: post_save.connect(create_profile, sender=User)
通过此重构,您已对代码库进行了三处更改:
-
第 4 行:
receiver
为from添加导入django.dispatch
。 -
第 8 行:将装饰器应用到
create_profile
,将其post_save
传递User
给sender
. 通过传递模型,您可以像以前一样将与模型相关post_save
的事件关联起来。User
.connect()
-
第 16 行:您删除了之前作为发送者连接的代码行,
post_save
因为User
您已经通过第 8 行提供给装饰器的参数建立了该关联。
请记住,您需要先保存新创建的Profile
对象才能使其存在。只有这样,您才能将新创建的用户添加.profile
到您的新user_profile
. 最后,您需要再次保存更改以将更新的关联传播到您的数据库。
注意:如果您对.add()
上面代码片段中的使用感到惊讶,那么再看看上一节中名为Alternative Implementation的可折叠部分。
恭喜,您已经成功设置了 Django 社交网络的大部分后端。您实现了用户和 Django 社交网络配置文件之间的模型关系!每次您创建新用户时,他们也会收到用户个人资料并立即关注他们自己的个人资料。此外,用户配置文件可以相互关注。但它有效吗?
在您的管理员中确认自动关联
返回您的管理界面并通过提供的表单创建一个新用户。您所要做的就是提供用户名并单击保存。例如,您可以添加另一个名为rainn 的用户:
当您检查用户的更改页面时,您会看到 Django 自动为新用户创建了一个配置文件,并将该配置文件添加到他们关注的配置文件列表中:
您可以看到用户关注了他们自己的个人资料,因为他们在“关注”列表中的个人资料名称具有灰色背景。
您现在可以通过 Django 管理界面创建新用户,他们也会自动收到关联的配置文件。Django 还将设置他们的个人资料以跟随自己,这将可以在他们的仪表板上显示他们自己的 dweets 旁边的其他人的 dweets。
您可以通过在关注列表中选择或取消选择配置文件名称并单击保存来更改用户关注的配置文件。要选择多个配置文件或取消选择特定配置文件,您需要Ctrl在 Windows 和 Linux 或CmdmacOS 上按住,同时单击配置文件名称。
注意:您可以稍后通过 Django 的内置用户管理系统设置前端身份验证,并且您无需在后端进行任何更改即可使功能继续按预期工作。
当有人创建新用户帐户时,他们将收到个人资料,此外,他们将免费获得第一个自我关注!
但是这里还没有什么可看的。到目前为止,您只潜伏在 Django 管理员中。也许您开始厌倦 Django 提供的预构建页面,并渴望编写一些Django 模板以了解如何在应用程序的用户界面中显示这些模型关系。
这就是您将在本教程系列的第二部分中进行的工作!您将开始构建您的 Web 应用程序的前端,并且您将学习如何使用 CSS 框架Bulma使其看起来更好。
结论
恭喜!至此,您已经完成了使用 Django 构建基本社交网络的本教程系列的第一部分。
在本教程系列的第一部分中,您学习了如何:
- 实现Django模型之间的一对一和多对多关系
- 使用自定义模型扩展 Django用户模型
Profile
- 自定义Django 管理界面
您还获得了设置 Django 项目以及与此相关的任务的额外实践。您已经练习阅读 Django 错误消息并根据它们提供的信息找到解决方案。
您可以通过单击下面的链接并转到文件夹来下载该项目第一部分的代码source_code_final/
:
使用 Django 构建基本社交网络的后续步骤
现在您已经完成了本系列的第一部分,您可以继续阅读第二部分,您将在其中构建一个使用 Bulma 样式的 Django 前端。在本教程系列的第二部分中,您将为您的用户配置文件构建前端页面并使它们看起来不错。
当您继续处理此项目时,您可以参考本教程系列的这一部分,查阅您在项目概述中起草的计划,并在此过程中更新您的计划。
- 点赞
- 收藏
- 关注作者
评论(0)