本章我们将首次使用数据库来构建基本的留言板应用,用户可以在其中发布和阅读短消息。我们将探索Django强大的内置管理界面,它提供了可视化的方式来对我们的数据进行修改。
强大的Django ORM(Object-Relational Mapper)内置了对多个数据库后端的支持。PostgreSQL、MySQL、MariaDB、Oracle或SQLite。这意味着可以在models.py文件中编写相同的Python代码,它将自动正确翻译成每个数据库。唯一需要的配置是更新我们config/settings.py文件中的DATABASES部分。
对于本地开发,Django默认使用SQLite,因为它是基于文件的,因此使用起来比其他数据库选项简单得多。
建立留言板应用
$ mkdir mb && cd mb
$ django-admin startproject config .
$ python manage.py startapp posts
$ vi config/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'posts', # new
]
$ python manage.py migrate
为了确保数据库反映项目的当前状态,你需要在每次更新模型时运行migrate(以及makemigrations)。
创建数据库模型
创建一个数据库模型,在那里我们可以存储和显示来自用户的帖子。Django的ORM会自动为我们把这个模型变成数据库表。
post/models.py文件
# posts/models.py
from django.db import models
class Post(models.Model):
text = models.TextField()
我们已经创建了数据库模型,叫做Post,它有一个数据库字段text。我们还指定了它要容纳的内容类型,即TextField()。Django提供了许多支持常见内容类型的模型字段,如字符、日期、整数、电子邮件等等。
我们用makemigrations命令创建一个迁移文件。迁移文件为数据库模型的任何变化创建参考,这意味着我们可以跟踪变化,并在必要时调试错误。
$ python manage.py makemigrations posts
$ python manage.py migrate
如果运行 python manage.py makemigrations,就会为整个Django项目创建迁移文件。
Django管理
Django的杀手锏之一是其强大的内置管理界面,它提供了可视化的方式来与数据互动。Django最初是作为报纸CMS(Content Management System内容管理系统)而建立的。当时的想法是,记者们可以在管理编写和编辑他们的故事,而不需要接触 "代码"。随着时间的推移,内置的管理应用程序已经发展成为神奇的、开箱即用的工具,用于管理Django项目的各个方面。
要使用Django管员,我们首先需要创建超级用户。在你的命令行控制台中,输入python manage.py createsuperuser,并对提示的用户名、电子邮件和密码做出回应。
$ python manage.py createsuperuser
用python manage.py runserver重启Django服务器,在你的网页浏览器中进入http://127.0.0.1:8000/admin/。你应该看到管理员的登录界面。
但是我们的帖子没有显示在管理主页面上!必须更新一个应用程序的admin.py文件,使其出现在管理员中。
在你的文本编辑器中打开post/admin.py,添加以下代码,以便显示Post模型。
# posts/admin.py
from django.contrib import admin
from .models import Post
admin.site.register(Post)
Django现在知道它应该在管理页面上显示我们的post应用程序和它的数据库模型Post。如果你刷新你的浏览器,你会看到它出现了。
点击帖子对面的+添加按钮,在文本表格字段中输入你自己的内容。
然后点击 "保存 "按钮,这将重定向到主帖子页面。然而,如果你仔细观察,就会发现问题:新条目被称为 "Post object",这不是很好的描述!
让我们来改变它。在 posts/models.py 文件中,添加一个新的函数 str,如下所示。
# posts/models.py
from django.db import models
class Post(models.Model):
text = models.TextField()
def __str__(self):
return self.text[:50]
这将显示文本字段的前50个字符。
视图/模板/URLs
现在我们想列出我们数据库模型的内容,Django配备了基于通用类的ListView。
在post/views.py文件中输入下面的Python代码。
# posts/views.py
from django.views.generic import ListView
from .models import Post
class HomePageView(ListView):
model = Post
template_name = 'home.html'
增加模板
$ mkdir templates
$ vi templates/home.html
<!-- templates/home.html -->
<h1>Message board homepage</h1>
<ul>
{% for post in object_list %}
<li>{{ post.text }}</li>
{% endfor %}
</ul>
最后一步是设置我们的URLConfs。
config/urls.py文件
# config/urls.py
from django.contrib import admin
from django.urls import path, include # new
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('posts.urls')), # new
]
然后在post应用程序中创建urls.py文件。
# posts/urls.py
from django.urls import path
from .views import HomePageView
urlpatterns = [
path('', HomePageView.as_view(), name='home'),
]
用python manage.py runserver重新启动服务器,并导航到我们的主页,现在它列出了我们的留言板帖子。
测试
以前,我们只测试静态页面,所以我们使用SimpleTestCase。但现在有数据库,需要使用TestCase。我们不需要在我们的实际数据库上运行测试,而是可以建立一个单独的测试数据库,用样本数据填充,然后针对它进行测试,这肯定是更安全、更快的方法。
# posts/tests.py
from django.test import TestCase
from django.urls import reverse
from .models import Post
class PostModelTest(TestCase):
def setUp(self):
Post.objects.create(text='just a test')
def test_text_content(self):
post=Post.objects.get(id=1)
expected_object_name = f'{post.text}'
self.assertEqual(expected_object_name, 'just a test')
class HomePageViewTest(TestCase): # new
def setUp(self):
Post.objects.create(text='this is another test')
def test_view_url_exists_at_proper_location(self):
resp = self.client.get('/')
self.assertEqual(resp.status_code, 200)
def test_view_url_by_name(self):
resp = self.client.get(reverse('home'))
self.assertEqual(resp.status_code, 200)
def test_view_uses_correct_template(self):
resp = self.client.get(reverse('home'))
self.assertEqual(resp.status_code, 200)
self.assertTemplateUsed(resp, 'home.html')