连接Models、Views和Template来提供动态内容。在本章中,将通过在主页上显示类别的过程,然后创建专门的类别页面来显示相关的链接列表。
1. Workflow:数据驱动页面
在Django中创建一个数据驱动的网页,五个主要步骤。
(1) 在views.py模块中,import
希望使用的模型
(2) 在view函数中,查model以获得想要显示的数据
(3) 在view中,将model的结果传递到template的上下文中
(4) 创建/修改template,使其显示来自上下文的数据
(5) 如果还没有这样做,将URL映射到view
2. 在Rango主页显示category
(1) import需要的Models
打开rango/views.py,在文件的顶部其他import
之后,从rango的models.py文件中导入Category模型
# Import the Category model
from rango.models import Category
(2)&(3) 修改Index view
def index(request):
# 查询数据库中当前存储的所有类别的列表
# 按照喜欢的数量降序排列类别
# 只检索前5个——如果小于5则检索全部。
# 将列表放在context_dict字典中(带有粗体消息!) -- 它将被传递给模板引擎
# 查询“类别”模型可检索前5个类别
# order_by: 排序; 减号: 降序排列
category_list = Category.objects.order_by('-likes')[:5]
context_dict = {}
context_dict['boldmessage'] = 'Crunchy, creamy, cookie, candy, cupcake!'
context_dict['categories'] = category_list
# 渲染response并将其发送回去!
return render(request, 'rango/index.html', context=context_dict)
(4) 修改Index Template
更新template/index.html
<!DOCTYPE html>
{% load staticfiles %}
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>Rango says...</h1>
<div>
hey there partner! <br />
<strong>{{ boldmessage }}</strong><br />
</div>
<div>
{% if categories %}
<ul>
{% for category in categories %}
<li>{{ category.name }}</li>
{% endfor %}
</ul>
{% else %}
<strong>There are no categories present.</strong>
{% endif %}
</div>
<div>
<a href="/rango/about/">About Rango</a><br />
<img src="{% static 'images/rango.jpg' %}" alt="Picture of Rango" />
</div>
</body>
</html>
(4) runserver
3. 创建详细信息页面
根据Rango的要求,我们还需要显示与每个类别相关联的页面列表
首先,必须创建一个新view。这个新视图必须被参数化。
我们还需要创建URL模式和URL字符串来编码类别名称
(1) 更新Category Table与一个slug字段
要创建可读的url,我们需要在Category模型中包含一个slug字段:
首先,从Django中导入函数slugify,它将用连字符替换空白,绕过百分比编码的问题
例如“how do i create a slug in django”变成了“how-do-i-create-a-slug-in django”
其次重写Category模型的save():
这个被重写的函数将调用slugify()函数并使用它更新新的slug字段。需要注意的是,每当category名发生变化时,slug也会发生变化——save()方法总是在创建或更新一个Django模型的实例时被调用。如下所示更新Category模型:
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
slug = models.SlugField()
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
class Meta:
verbose_name_plural = 'categories'
def __str__(self):
return self.name
(2) 迁移
$ python manage.py makemigrations rango
由于我们没有为该段代码提供默认值,并且我们在模型中已经有了现有的数据,因此makemigration命令将为您提供两个选项。选择提供默认值的选项(选项1),并输入一个空字符串——用两个引号表示(即’’)
然后迁移更改,并再次运行填充脚本以更新新的slug字段;重启server
$ python manage.py migrate
$ python populate_rango.py
$ python manage.py runserver
(3)定制管理界面
输入Category名称时,它会自动预填充slug字段 ⇒ 用以下代码更新rango/admin.py
class CategoryAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug':('name',)}
admin.site.register(Category, CategoryAdmin) #替换admin.site.register(Category)
(4) Categpry Page Workflow
为单个类别创建页面 --> 能够看到与一个类别相关联的页面。要实现类别页面,以便可以使用URL模式/rango/category/category-name-slug/访问它们,我们需要执行以下步骤:
a. 将Page模型导入rango/views.py中
from rango.models import Page
b. 在rango/views.py中创建一个名为show_category()的新view。show_category () 视图将接受第二个参数category_name_slug,它将存储编码后的类别名称。
•我们将需要辅助函数来编码和解码category_name_slug
def show_category(request, category_name_slug):
# Create a context dictionary which we can pass
# to the template rendering engine.
context_dict = {}
try:
# Can we find a category name slug with the given name?
# If we can't, the .get() method raises a DoesNotExist exception.
# The .get() method returns one model instance or raises an exception.
category = Category.objects.get(slug=category_name_slug)
# Retrieve all of the associated pages.
# The filter() will return a list of page objects or an empty list.
pages = Page.objects.filter(category=category)
# Adds our results list to the template context under name pages.
context_dict['pages'] = pages
# We also add the category object from # the database to the context dictionary.
# We'll use this in the template to verify that the category exists.
context_dict['category'] = category
except Category.DoesNotExist:
# We get here if we didn't find the specified category.
# Don't do anything # the template will display the "no category" message for us.
context_dict['category'] = None
context_dict['pages'] = None
# Go render the response and return it to the client.
return render(request, 'rango/category.html', context=context_dict)
c. 创建一个新模板,templates/rango/category.html
<!DOCTYPE html>
<html>
<head>
<title>Rango</title>
</head>
<body>
<div>
{% if category %}
<h1>{{ category.name }}</h1>
{% if pages %}
<ul>
{% for page in pages %}
<li><a href="{{ page.url }}">{{ page.title }}</a></li>
{% endfor %}
</ul>
{% else %}
<strong>No pages currently in category.</strong>
{% endif %}
{% else %}
The specified category does not exist.
{% endif %}
</div>
</body>
</html>
d. 更新Rango的urlpatterns,将新的分类视图映射到 rango / urls. py
将category_name_url参数的值传递给show_category()函数
修改rango/urls.py文件并按如下方式更新urlpatterns元组
urlpatterns = [
path('', views.index, name='index'),
path('about/', views.about, name="about"),
path('category/<slug:category_name_slug>/', views.show_category, name='show_category'),
# 我们想要匹配一个字符串,它是一个slug,并将它赋值给变量category_name_slug
]
(5) 修改Index Template
我们的index页面模板需要更新,以便它链接到列出的类别页面
我们可以更新index.html模板,让它包含一个通过slug链接到category页面的链接
<ul>
{% for category in categories %}
<li>
<a href="/rango/category/{{ category.slug }}/">{{ category.name }}</a>
</li>
{% endfor %}
</ul>