说明:文章中写的{百分号 百分号}具体指代

由于渲染模板的问题,导致指令混淆,特在此说明!

Django 管理网站

创建超级用户

Django允许创建具备所有权限的用户–超级用户,权限决定了用户可以执行的操作。

为创建超级用户,需要执行下面操作:

1
python manage.py createsuperuser

注:在创建时,系统会提示输入用户名和秘密

向管理网站注册模型

Django会自动在管理网站加入一些模型,入UserGroup,但自己创建的模型必须手工进行注册

在创建应用程序flightbook时,Djangomodels.py所在目录中创建了一个名为admin.py的文件:

1
2
3
from django.contrib import admin
from flightbook.models import model_name
admin.site.register(model_name)

完成上述操作后,就会在Django管理网站上管理model_name我们的模型;可以通过https://localhost:8000/admin 进入管理页面

注:如果这个时候在console中执行 python manage.py runserver,则我们无法看到后台管理页面上的新model_name

我们要做的就是迁移数据库

1
python manage.py makemigrations app_name

注:切记,在每次更新模型时都需要做数据库的迁移操作,以便关联数据库

创建网页:以学习笔记首页为例

使用Django创建网页的过程通常分为三个阶段:定义URL、编写视图和编写模板。首先必须定义URL模式,它描述了URL是如何设计的,让Django知道如何将浏览器请求与URL匹配,以确定返回那个页面。每个URL映射到特定的视图–视图函数获取并处理网页所需的数据,视图函数通常调用一个模板,后者生成浏览器能够理解的网页。

映射URL

用户通过在浏览器中输入url以及单击链接来请求网页,因此我们需要确定项目需要哪些URL。主页的url很重要,他用来访问项目的基础url,当前基础url返回默认的Django网站。

在项目主文件夹learning_log中的文件urls.py如下:

1
2
3
4
5
6
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('',include('learning_logs.urls',namespace='learning_logs') # 新增行
]

注:其中的实参namespace,让learning_logs中的url同项目中的其他url区分开

默认的urls.py包含在文件夹learning_log中,现需要在learning_logs中创建另一个urls.py文件:

1
2
3
4
5
6
7
# 定义learning_logs的url模式
from django.conf.urls import url

from . import views
urlpatterns = [
url(r'^$',views.index,name='index')
]

注:url()的第二个实参,指定了要调用的视图函数;第三个实参将这个url模式的名称指定为index

编写视图

视图函数接受请求信息,准备好生成网页所需的数据,再将这些数据发送给浏览器–通常是使用了定义了网页时什么样的模板实现的

learning_logs中的文件views.py是执行python manage.py startapp时生成的

1
2
3
4
5
6
from django.shortcuts import render   # render()函数根据视图提供的数据渲染进行渲染
# 在这里创建视图

def index(request):
"""学习笔记的主页"""
return render(request,'learning_logs/index.html')

注:Django将在文件views.py中查找index()函数,再将请求对象传递给这个视图函数

编写模板

模板定义了网页的结构。模板指定了网页是什么样的,而当网页被请求时,Django将填入相关的数据,模板能够访问视图提供的任何数据

随便写一个index.html就行

创建其他网页

制定创建网页的流程后,可以开始扩充学习笔记项目了,创建两个显示数据的网页,其中一个列出所有的主题,另一个显示特定主题的所有条目。对于每个网页,都将指定url模式,编写一个视图函数,并编写一个模板。因此我们先创建一个父模板,项目中的其他模板都继承它

模板继承

父模板

创建base.html模板,并存储在index.html所在目录中,这个页面包含所有页面都有的元素;其他模板都继承base.html

1
2
3
4
5
6
{% draw %} <!--注意-->
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a> <!--创建一个包含项目名的段落,也是一个到主页的链接-->
</p>
{% block content %}{% endblock content %}
{% endraw %} <!--注意-->

为创建链接,我们使用了一个模板标签,用大括号和百分号{百分号 百分号}表示。模板标签是一小段代码,生成要在网页中显示的信息,其中{百分号 url 'learning_logs:index' 百分号}生成一个url,该urllearning_logs/urls.py中定义的名为indexurl相匹配;让模板标签来生成url,可让链接保持最新容易的多。要修改项目中的url,只需要修改urls.py中的URL模式即可,这样网页被请求时,Django将自动插入修改后的url;对于==块标签==,块名是content,是一个占位符,其中包含的信息由子模板指定。

子模版

先更改index.html,使得其继承base.html

index.html

1
2
3
4
5
6
{% draw %} <!--注意-->
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Learning Log helps you keep track of your learning,for any topic you are learning about.</p>
{% endblock content %}
{% draw %} <!--注意-->

注1:子模板的第一行必须包含标签{百分号 entends 百分号},让Django知道继承了哪个父模板,文件base.html位于文件夹learning_logs中,因此父模板路径必须包含learning_logs,这行代码导出了模板base.html中的所有内容,让index.html能够指定要在content块预留的空间中添加的内容

注2:插入了一个{百分号 block 百分号}标签,以定义content块,不是从父模板继承的内容都包含在content中,在这里是一个描述项目学习笔记的一个段落

特点

在子模板中,只需包含当前网页特有的内容,这不仅简化了模板,还使得网站修改起来容易的多,要修改很多网页都包含的元素,只需要在父模板中修改该元素

显示所有主题的页面

显示全部主题的网页以及显示特定主题中条目的网页

url模式

首先来定义一个显示所有主题的页面的额url

修改learning_log/urls.py

1
2
3
4
5
6
7
8
# 定义learning_logs的url模式
from django.conf.urls import url

from . import views
urlpatterns = [
url(r'^$',views.index,name='index')
url('^topics/$',views.topics,name='topics') #显示所有主题
]

注:该url(显示所有主题的)与该模式匹配的请求都交给views.py中的函数topics()进行处理

视图

函数topics()需要从数据库中获取一些数据,并将其发送给模板,需要在views.py中添加:

1
2
3
4
5
6
7
8
9
10
11
from django.shortcuts import render
from .models import Topic
# Create your views here.
def index(request):
"""学习笔记的主页"""
return render(request,'learning_logs/index.html')
def topics(request):
"""显示所有主题"""
topics = Topic.objects.order_by('date_added')
context = {'topics':topics}
return render(request,'learning_logs/topics.html',context)

注1:首先导入了与所需数据相关联的模型,函数topics()包含一个形参:Django从服务器那里收到的request对象。我们查询数据库--请求Topic对象,并按属性date_added对其进行排序

注2:{'topics':topics}定义了一个将要发送给模板的上下文。上下文是一个字典,其中的键是用来访问的数据的名称,而值是要发送给模板的数据;创建使用数据的网页时,除了对象request和模板的路径外,还要将变量content传递给render()

模板

显示所有主题的页面的模板接受字典context,以便能够使用topics()提供的数据,先创建一个topics.html,存储在index.html所在的目录中

topics.html

1
2
3
4
5
6
7
8
9
10
11
12
13
{% draw %} <!--注意-->
{% entends "learning_logs/base.html" %}
{% block content %}
<p>Topics</p>
<ul>
{% for topic in topics %}
<li>{ topic }</li> <!--俩大括号-->
{% empty %}
<li>No topics have been added yet.</li>
{% endfor %}
</ul>
{% endblock %}
{% endraw %} <!--注意-->

注1:首先使用标签{百分号 entends "learning_logs/base.html" 百分号}来继承base.html,再来定义content块,网页的主题是一个项目列表,列出了用户输入的主题。

注2:使用了一个for循环的一个模板标签,遍历字典context中的列表topics。

注3:使用了一个模板标签{百分号 empty 百分号},它告诉Django在列表topics为空时怎么办:这是一条打印信息,告诉用户还没有添加任何主题

现在修改父模板,使其包含显示所有主题的页面的链接

base.html

1
2
3
4
5
6
7
{% draw %} <!--注意-->
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a>- <!--创建一个包含项目名的段落,也是一个到主页的链接-->
<a href="{% url 'learning_logs:topics' %}">Topics</a> # 新增
</p>
{% block content %}{% endblock content %}
{% endraw %} <!--注意-->

显示特定主题的页面

创建特定主题的页面–显示giant主义的名称以及该主题的所有条目。将定义一个新的url模式,编写一个视图并创建一个模板。

url模式

显示特定主题的url模式与前面的所有url模式稍微有些不同,因为它将使用主题的id属性来之处请求的是哪个主题,比如用户要查看主题chess(其id为1)的详细页面,url将为https://localhost:8000/topics/1

url的匹配模式,包含在learning_logs/urls.py

1
2
3
4
5
6
7
8
9
# 定义learning_logs的url模式
from django.conf.urls import url

from . import views
urlpatterns = [
url(r'^$',views.index,name='index'),
url(r'^topics/$',views.topics,name='topics') , #显示所有主题
url(r'^topics/(?P<topic_id>\d+)/$',views.topic,name='topic'), # 新增
]

注:r'^topics/(?P<topic_id>\d+)/$ 这是一段正则表达式,r’‘是为了让Django将这个字符串视为原始字符串,并指出正则表达式包含在引号内;这个表达式的第二部分/(?P<topic_id>\d+)/包含在与两个斜杠内的整数匹配,并将这个整数存在一个名为topic_id的实参中;发现匹配时,Django将调用视图函数topic(),并将存储在topic_id中的值最为实参传递给它'

视图

函数topic()需要从数据库中获取指定的主题以及与之相关联的所有条目

views.py

1
2
3
4
5
6
7
8
9
10
11
# --snip--
def topics(request):
"""显示所有主题"""
topics = Topic.objects.order_by('date_added')
context = {'topics':topics}
return render(request,'learning_logs/topics.html',context)
def topic(request,topic_id): #新增函数
topic = Topic.objects.get(id=topic_id)
entries = topic.entry_set.order_by('-date_added')
context = {'topic':topic,'entries':entries}
return render(request,'learning_logs/topic.html',context)

注:这是第一个除实参外还包汉形参的视图函数,这个函数接受正则表达式(?P<topic_id>\d+)捕获的值,并将其存储到topic_id中;使用get()获取指定的主题;'-date_added'是按照时间降序排列,先显示最近的条目;主题和条目存储在字典中,然后返回给模板topic.html

模板

这个模板需要显示主题的名称和条目的内容

新建topic.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{% draw %} <!--注意-->
{% extends 'learning_logs/base.html' %}

{% block content %}
<p>Topic:{ topic }</p> <!--俩大括号-->
<p>Entries:</p>
<ul>
{% for entry in entries %}
<li>
<p>{ entry.date_added|date:'M d,Y H:i' }</p> <!--俩大括号-->
<p>{ entry.date.text|linebreaks }</p> <!--俩大括号-->
</li>
{% empty %}
<li>There are no entries for this topic yet</li>
{% endfor %}
</ul>
{% endblock content %}
{% endraw %} <!--注意-->

注:继承了base.html页面;同时显示当前的主题存储在中,那为什么可以使用topic?因为它包含在字典context中,之后遍历即可;每个项目列表项会列出两项信息:时间戳和完整地文本。为列出时间戳,显示了属性date_added的值;在Django中,|表示模板过滤器--对模板变量的值进行修改的函数。过滤器date:'M d,Y H:i'以这样的格式显示时间戳:January 1,2019 11:11,而后是显示text的值,而不仅仅显示entry的前50个字符;过滤器linebreaks将包含换行符的长条目转换为浏览器能够理解的格式,以免显示为一个不间断的文本块。

将显示所有主题的页面中的每个主题都设置链接

修改topics.html

1
2
3
4
5
6
7
8
9
10
11
12
13
{% draw %} <!--注意-->
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics</p>
<ul>
{% for topic in topics %}
<li><a href="{% url 'learning_logs:topic' topic.id %}">{ topic }</li> # 修改,此处为俩大括号
{% empty %}
<li>No topics have been added yet.</li>
{% endfor %}
</ul>
{% endblock %}
{% endraw %} <!--注意-->