有两种方法可以在我们的报纸网站上添加评论。第一种是创建专门的评论应用,并将其与文章链接起来,这样有点过度的工程化。相反,我们可以简单地在我们的文章应用中添加叫做评论的额外模型,并通过外键将其链接到文章模型上。
模型
在现有的数据库中添加表:Comment。它与Article有多对一关系。传统上,外键字段的名称只是它所链接的模型,所以这个字段将被称为article。另外两个字段将是评论和作者。
打开 articles/models.py 文件,在现有代码下面添加以下内容。
articles/models.py
# articles/models.py
...
class Comment(models.Model): # new
article = models.ForeignKey(Article, on_delete=models.CASCADE)
comment = models.CharField(max_length=140)
author = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
)
def __str__(self):
return self.comment
def get_absolute_url(self):
return reverse('article_list')
执行数据迁移:
$ python manage.py makemigrations articles
$ python manage.py migrate
articles/admin.py
# articles/admin.py
from django.contrib import admin
from .models import Article, Comment # new
admin.site.register(Article)
admin.site.register(Comment) # new
然后用python manage.py runserver启动服务器,导航到我们的主页面http://127.0.0.1:8000/admin/。
在我们的应用程序 "Article "下,你会看到我们的两个表。Comments和Articles。点击Articles旁边的 "+添加"。你会看到在文章下有现有文章的下拉菜单,作者也是如此,在评论旁边有一个文本字段。
我们可以添加一个额外的管理字段,这样我们就可以在这个页面上看到评论和文章。但如果只是看到与一个单一的帖子模型相关的所有评论模型不是更好吗?事实证明,我们可以用Django的管理功能inlines来显示外键关系,这是一种很好的、可视化的方式。
有两个主要的inline视图。TabularInline和StackedInline。两者之间唯一的区别是显示信息的模板。在TabularInline中,所有的模型字段都出现在一行,而在StackedInline中,每个字段都有自己的一行。我们将实现这两种方式,所以你可以决定你喜欢哪一种。
在你的文本编辑器中更新 articles/admin.py 如下。
# articles/admin.py
from django.contrib import admin
from .models import Article, Comment
class CommentInline(admin.StackedInline): # new
model = Comment
class ArticleAdmin(admin.ModelAdmin): # new
inlines = [
CommentInline,
]
admin.site.register(Article, ArticleAdmin) # new
admin.site.register(Comment)
现在回到 http://127.0.0.1:8000/admin/ 的主管理页面,点击 "文章"。选择你刚刚添加评论的文章。
我们可以在一个地方看到并修改我们所有相关的文章和评论。请注意,默认情况下,Django管理员会在这里显示3行空行。你可以改变出现额外字段的默认数量。所以,如果你想默认没有字段,代码会是这样的。
articles/admin.py
# articles/admin.py
...
class CommentInline(admin.StackedInline):
model = Comment
extra = 0 # new
我个人更倾向于使用TabularInline,这样更节省空间:
articles/admin.py
# articles/admin.py
from django.contrib import admin
from .models import Article, Comment
class CommentInline(admin.TabularInline): # new
model = Comment
class ArticleAdmin(admin.ModelAdmin):
inlines = [
CommentInline,
]
admin.site.register(Article, ArticleAdmin)
admin.site.register(Comment)
刷新管理页面,你会看到新的变化:每个模型的所有字段都显示在同一行
模板
由于Comment存在于我们现有的文章应用程序中,我们只需要更新现有的article_list.html和article_detail.html的模板来显示我们的新内容
我们要做的是显示与特定文章相关的所有评论。这被称为 "查询",因为我们在向数据库询问特定的信息。在我们的案例中,使用外键工作,我们想遵循一个向后的关系:为每一篇文章查找相关的评论模型。
Django有内置的语法用于 "向后 "跟踪关系,称为FOO_set(following relationships “backward”),其中FOO是小写的源模型名称。所以对于我们的Article模型,我们可以使用article_set来访问该模型的所有实例。
但我个人非常不喜欢这种语法,因为我觉得它很混乱,而且不直观。更好的方法是给我们的模型添加related_name属性,让我们明确地设置这种反向关系的名称。让我们来做这件事。
首先,给我们的评论模型添加一个related_name属性。一个好的默认值是把它命名为持有外键的模型的复数。
# articles/models.py
...
class Comment(models.Model):
article = models.ForeignKey(
Article,
on_delete=models.CASCADE,
related_name='comments', # new
)
comment = models.CharField(max_length=140)
author = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
)
def __str__(self):
return self.comment
def get_absolute_url(self):
return reverse('article_list')
再次执行数据迁移。
理解查询需要一些时间,所以如果反向关系的概念令人困惑,也不要担心。我将告诉你如何实现所需的代码。而一旦你掌握了这些基本情况,你就可以探索如何非常详细地过滤你的查询集,以便它们准确地返回你想要的信息。
在我们的article_list.html文件中,我们可以将我们的评论添加到卡片页脚中。注意,我已经把我们的编辑和删除链接移到了卡片正文中。要访问每个评论,我们要调用article.comments.all,这意味着首先要看文章模型,然后是评论,这是整个评论模型的相关名称,然后选择所有包含的评论。要适应这种在模板中引用外键数据的语法,可能需要一点时间
template/article_list.html
<!-- template/article_list.html -->
{% extends 'base.html' %}
{% block title %}Articles{% endblock title %}
{% block content %}
{% for article in object_list %}
<div class="card">
<div class="card-header">
<span class="font-weight-bold">{{ article.title }}</span> ·
<span class="text-muted">by {{ article.author }}
| {{ article.date }}</span>
</div>
<div class="card-body">
<!-- Changes start here! -->
<p>{{ article.body }}</p>
<a href="{% url 'article_edit' article.pk %}">Edit</a> |
<a href="{% url 'article_delete' article.pk %}">Delete</a>
</div>
<div class="card-footer">
{% for comment in article.comments.all %}
<p>
<span class="font-weight-bold">
{{ comment.author }} ·
</span>
{{ comment }}
</p>
{% endfor %}
</div>
<!-- Changes end here! -->
</div>
<br />
{% endfor %}
{% endblock content %}
刷新文章页面,http://127.0.0.1:8000/articles/,我们可以看到我们的新评论显示在页面上。
如果有更多的时间,我们现在会把重点放在表单上,这样用户就可以直接在文章/页面上写一篇新的文章,同时也可以添加评论。但本章的主要重点是演示外键关系在Django中的工作原理。
小结
我们的报纸应用程序现在已经完成了。它有强大的用户认证流程,使用了自定义的用户模型和电子邮件。由于使用了Bootstrap,外观得到了改进。同时还有文章和评论。我们甚至还在权限和授权方面做了一些尝试。
我们剩下的任务是在线部署它。我们的部署过程随着每一个连续的应用而变得越来越复杂,但我们仍然围绕着安全和性能采取了捷径。在下一章,我们将看到如何通过使用环境变量、PostgreSQL和额外的设置来正确部署Django网站。
网友评论