1.建立项目
Django是一个Web框架——一套用于帮助开发交互式网站的工具。响应网页请求,更轻松地读写数据库、管理用户等。
(1)制定规范
规范:我们要编写一个名为“学习笔记”的Web应用程序,让用户能够记录感兴趣的主题,并在学习每个主题的过程中添加日志条目。“学习笔记”的主页对这个网站进行描述,并邀请用户注册或登录。用户登录后,就可创建新主题、添加新条目以及阅读既有的条目。
(2)建立虚拟环境。要使用Django,需要建立一个虚拟工作环境(系统的一个位置),在其中安装包,并将其与其他Python包隔离。为项目新建一个目录learning_log,命令行窗口切换到这个目录,执行命令python -m venv ll_env,运行venv模块,使用它创建一个名为ll_env的虚拟环境。
(3)激活虚拟环境。使用命令:ll_env\Scripts\activate,停止使用虚拟环境,可执行命令deactivate或者直接关闭运行虚拟环境的终端。
(4)安装Django。创建并激活虚拟环境后,安装Django,执行命令:pip install Django==1.11
(5)在Gjango中创建项目。接下来在Gjango中创建项目,执行命令:django-admin.py startproject learning_log . ,命令末尾的句点让新项目使用合适的目录结构,这样开发完成后可轻松地将应用程序部署到服务器。执行命令后,learning_log下生成learning_log文件夹和文件manage.py(一个简单的程序,它接受命令并将其交给Django的相关部分去运行),learning_log文件夹下其中三个文件:settings.py(指定Django如何与你的系统交互以及如何管理项目),urls.py(告诉Django应创建哪些网页来响应浏览器请求),wsgi.py(帮助Django提供它创建的文件)。
(6)创建数据库。执行命令:python manage.py migrate,修改数据库称为迁移数据库,首次执行命令migrate时,将让Django确保数据库与项目的当前状态匹配。执行命令后,项目文件夹下创建新文件——db.sqlite3,SQLite是一种使用单个文件的数据库,是编写简单应用程序的理想选择,不用太关注数据库管理的问题。
(7)查看项目。核实Django是否正确创建了项目,执行命令:python manage.py runserver,浏览器输入http://localhost:8000/或者http://127.0.0.1:8000/查看返回的网页。若上述命令提示执行端口已被占用,执行命令python manage.py runserver 8001,端口若也不可用则逐渐增大端口号直到找到可用端口。
2.创建应用程序
Django项目由一系列应用程序组成,他们协同工作,让项目成为一个整体。
另打开一个终端窗口,进入项目目录learning_log,激活虚拟环境之后执行命令:python manage.py startapp learning_logs,该命令让Django建立创建应用程序所需的基础设施。命令执行成功后项目目录下新增文件夹learning_logs,其中models.py定义我们要在应用程序中管理的数据,admin.py和views.py也是重要的文件。
(1)定义模型:修改learning_logs文件夹下的models.py文件,添加了Topic类:
from django.db import models
# Create your models here. 代码层面,模型就是一个类
class Topic(models.Model): #继承了Model——Django中一个定义了模型基本功能的类
'''用户学习的主题'''
text = models.CharField(max_length=200) #CharField——由字符或文本组成的数据,限制长度为200个字符
date_added = models.DateTimeField(auto_now_add=True) #DateTimeField——记录日期和时间的数据,auto_now_add=True表示当用户创建新主题时,让Django把这个属性自动设置成当前日期和时间。
def __str__(self):
'''返回模型的字符串表示'''
return self.text
(2)激活模型:要使用模型,必须让Django将应用程序包含到项目中,故修改learning_log下的settings.py文件,修改INSTALLED_SPPS元祖(Django项目由这些应用程序组成),新增一个应用程序。
接下来让Django修改数据库,使其能够存储与模型Topic相关的信息,执行命令:python manage.py makemigrations learning_logs,makemigrations让Django确定该如何修改数据库,使其能够存储与我们定义的新模型相关联的数据。
命令执行成功后输出表明创建了一个名为0001_initial.py的迁移文件,这个文件将在数据库中为模型Topic创建一个表。
下面来应用这种迁移,让Django替我们修改数据库,执行命令:python manage.py migrate。
修改“学习笔记”管理的数据步骤:1.修改models.py;2.对learning_logs调用makemigrations;3.让Django迁移项目 migrate
(3)Django管理网站
a.创建超极用户(具备所有权限的用户),执行命令:python manage.py createsuperuser,设置用户名和密码等。
b.向管理网站注册模型
修改文件夹learning_logs下的admin.py文件
使用超级用户账户访问管理网站:http://localhost:8000/admin/,输入创建超级用户用户名和密码后进入主页。
c.添加主题:选择Topic下的add按钮添加依次添加两个主题Chess和Climbing。
(4)定义模型Entry:记录象棋和攀岩知识,需要为每个主题下创建多个条目,形成多对一关系,即多个条目可关联到同一个主题。修改learning_logs下的models.py文件:
from django.db import models
# Create your models here. 代码层面,模型就是一个类
class Topic(models.Model): #继承了Model——Django中一个定义了模型基本功能的类
'''用户学习的主题'''
text = models.CharField(max_length=200) #CharField——由字符或文本组成的数据,限制长度为200个字符
date_added = models.DateTimeField(auto_now_add=True) #添加主题的时间戳,DateTimeField——记录日期和时间的数据,auto_now_add=True表示当用户创建新主题时,让Django把这个属性自动设置成当前日期和时间。
def __str__(self):
'''返回模型的字符串表示'''
return self.text
class Entry(modes.Model):
'''学到的有关某个主题的具体知识'''
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)#外键是一个数据库术语,它应用了数据库中的另一条记录,这些代码将每个条目关联到特定的主题
text = models.TextField() #条目的内容
data_added = models.DateTimeField(auto_now_add=True) #添加条目的时间戳,让我们能按照创建顺序呈现条目
class Meta: #Meta存储用于管理模型的额外信息
verbose_name_plural = 'entries' #一个特殊属性,让Django在需要时使用Entries来表示多个条目
def __str__(self):
'''返回条目的字符串表示'''
return self.text[:50] + "..."
(5)迁移模型Entry。然后激活模型:执行命令python manage.py makemigrations learning_logs, python manage.py migrate
(6)向管理网站注册Entry:修改admin.py文件。刷新浏览器页面,新增Entry,点击add键为Chess添加两个条目,为Climbing添加一个条目。
admin.py 代码如下:
from django.contrib import admin
from learning_logs.models import Topic, Entry
admin.site.register(Topic) #让Django通过管理网站管理我们的模型
admin.site.register(Entry)
(7)Django Shell:我们在网页上输入一些数据之后,就可通过交互式终端会话以编程方式查看这些数据了,这种交互式环境称为Django shell。执行命令:python manage.py shell,就能启动一个Python解释器,在简单的shell环境中排除故障比在生成网页的文件中排除故障容易得多。我们主要使用shell来熟悉对存储在项目中的数据进行访问的Django语法。
Topic.objects.all(),获取模型Topic的所有实例,返回的是一个列表,称为查询集。
Topic.objects.get(id=1),通过对象ID,获取该对象并查看其任何属性。
t.entry_set.all(),查看与主题相关的条目。为通过外键关系获取数据,可使用相关模型的小写名称、下划线和单词set。之前在Entry的定义中定义了外键topic。
3.创建网页:学习笔记主页
使用Django创建网页的过程通常分为三个阶段:定义URL、编写视图和编写模板。首先必须定义URL模式,URL模式描述了URL是如何设计的。每个个URL都被映射到特定的视图+视图函数获取并处理网页所需的数据。视图函数通常调用一个模板,后者生成浏览器能够理解的网页。
(1)映射URL。当前基础URL(http://localhost:8000/)返回默认的Django网站,接下来我们会将这个基础URL映射到“学习笔记”的主页。
修改learning_log下的urls.py,admin.site.urls模块定义了可在管理网站中请求的所有URL。namespace是的learnin_logs的URL同项目中的其他URL区分开来。
learning_log文件夹,urls.py 代码如下:
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'', include('learning_logs.urls', namespace='learning_logs')),
]
修改learning_logs下创建一个urls.py文件,写入以下代码。函数url,使用它来讲URL映射到视图;导入模块views,其中的句点表示让Python从当前的urls.py模块所在文件夹中导入视图。实际的URL模式是一个对函数url()的调用。函数的三个参数:参数1是一个正则表达式,定义了Django可查找的模式;参数2是指定要调用的视图函数;参数3是讲这个URL模式的名称指定为index。请求的URL与正则表达式匹配时,Django将调用view.index这个视图函数。app_name的值是为了与项目下面的urls.py中的namespace匹配上。
解析正则表达式r’^$'
- r表示让Python将接下来的字符串视为原始字符串; 引号告诉Python正则表达式始于和终于何处;
- 脱字符(^)表示让Python查看字符串的开头;
- 美元符号让Python查看字符串的末尾。
- 意义:这个正则表达式让Python查找开头和末尾之间没有任何东西的URL,因此这个正则表达式与基础URL匹配。
learning_logs文件夹,urls.py 代码如下:
'''difine the URL model of learning_logs'''
from django.conf.urls import url
from . import views
urlpatterns = [
# index
url(r'^$', views.index, name='index'),
]
app_name = 'learning_logs'
(2)编写视图,修改learning_logs下的views.py文件,render函数,根据视图提供的数据渲染响应。代码中的render()接收两个实参:原始请求对象,一个可用于创建网页的模板。
learning_logs文件夹, views.py 代码如下:
from django.shortcuts import render
def index(request):
'''the index page of Learning Log'''
return render(request, 'learning_logs/index.html')
(3)编写模板。在learning_logs下新建文件夹templates,templates下新建文件夹learning_logs,然后在learning_logs下新建index.html文件。当请求这个项目的基础URL——http://localhost:8000/,将看到配置的index.html网页,而不是默认的Django网页。Django接受请求的URL,发现该URL与模式r’^$'匹配,因此调用函数views.index(),这将使用index.html包含的模板来渲染网页。
<p>Learning Log</p>
<p>Learning Log helps you keep track of your learning, for any topic you're
learning about.</p>
4.创建其他网页:创建两个显示数据的网页,一个列出所有的主题,一个显示特定主题的所有条目。对于每个网页都指定URL模式,编写一个视图函数,并编写一个模板。首先我们创建一个父模板,项目中其他模板都继承它。
(1)模板继承。父模板中包含所有页面都有的元素。子模板继承父模板后,只需包含当前网页特有的内容。
a.父模板:base.html,存储在index.html所在目录中。
base.html创建了一个包含项目名的段落,也是一个到主页的链接。模板标签是由大括号和百分号({% %})表示的,是一小段代码,生成要在网页中显示的信息。文件的模板标签生成一个URL,这个URL与learning_logs/urls.py中定义的名为index的URL模式匹配。此处learning_logs是一个命名空间,而index是该命名空间中一个名称独特的URL模式。然后是一对快标签,块名为content,是占位符。标签内的内容将由子模板决定。父模板可预留多个块的空间,子模板根据需要定义相应数量的块。
base.html 代码如下:
<p>
<a href="{%url 'learning_logs:index'%}">Learning Log</a>
</p>
{% block content %}{% endblock content %}
b.子模块:第一行必须包含标签{% extends %}来告诉Django其继承的父模板。然后在content块预留的空间中添加子模板自己独特的内容。{% endblock content %}指出了内容定义的结束位置。
index.html 代码如下:
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Learning Log helps you keep track of your learning, for any topic you're
learning about.</p>
{% endblock content %}
(2)显示所有主题的页面
a.URL模式,修改learning_logs下的urls.py,匹配模式:基础URL后面跟着topics。
'''difine the URL model of learning_logs'''
from django.conf.urls import url
from . import views
urlpatterns = [
# index
url(r'^$', views.index, name='index'), #http://localhost:8000/
# topics
url(r'^topics/$', views.topics, name='topics'), #http://localhost:8000/topics/
]
app_name = 'learning_logs'
b.视图,修改learning_logs下的views.py,Topic.object.order_by(‘date_added’):查询数据库——请求提供Topic对象,并按相应属性date_added排序。context是一个要发给模板的上下文。它是一个字典,键是我们将在模板中用来访问数据的名称,而值是我们要发送给模板的数据。
from django.shortcuts import render
from .models import Topic
def index(request):
'''the index page of Learning Log'''
return render(request, 'learning_logs/index.html')
def topics(request):
'''show all topics'''
topics = Topic.objects.order_by('date_added')
context = {'topics': topics}
return render(request, 'learning_logs/topics.html', context)
c.模板:创建topics.html文件,并存储到index.html所在目录中。所有显示主题的页面接受字典context。标签ul为项目列表,也称无序列表。每个for循环都必须使用{% end for%}标签来显式地指出其结束位置。在模板中,循环类似以下:
在模板中打印变量,需要将变量名用双花括号括起来。模板标签{% empty %} 告诉Django在列表topics为空时该怎么办:这里是打印一条消息。
topics.html 代码如下:
{% extends "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 content %}
修改父模板 base.html 代码如下:
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a> -
<a href="{% url 'learning_logs:topics' %}">Topics</a>
</p>
{% block content %}{% endblock content %}
(3)显示特定主题的页面
a.URL模式,修改learning_logs下的urls.py,为了匹配类似http://localhost:8000/topics/1/ 的url,代码中匹配的正则表达式(?P<topic_id>\d+)是为了匹配整数1,这部分表达式两边的括号捕获URL的值,?P<topic_id>是将匹配的值存储到topic_id中,表达式\d+表示与两个斜杠内的任何数字都匹配,不管这个数字多少位。
urls.py 代码如下:
'''difine the URL model of learning_logs'''
from django.conf.urls import url
from . import views
urlpatterns = [
# index
url(r'^$', views.index, name='index'), #http://localhost:8000/
# topics
url(r'^topics/$', views.topics, name='topics'), #http://localhost:8000/topics/
# topic
url(r'^topics/(?P<topic_id>\d+)$', views.topic, name='topic'), #http://localhost:8000/topics/1/
]
app_name = 'learning_logs'
b.视图,修改learning_logs下的views.py,代码如下:
Topic.objects.get()来获取指定的主题。
from django.shortcuts import render
from .models import Topic
def index(request):
'''the index page of Learning Log'''
return render(request, 'learning_logs/index.html')
def topics(request):
'''show all topics'''
topics = Topic.objects.order_by('date_added')
context = {'topics': topics}
return render(request, 'learning_logs/topics.html', context)
def topic(request, topic_id):
'''show single topic and all entries'''
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)
c.模板,新建topic.html,存储到index.html所在的目录中。在Django模板中,竖线(|)表示模板过滤器——对模板变量的值进行修改的函数。过滤器date: ‘M d, Y H:i’ 以这样的格式显示时间戳:January 1, 2015 23:00。过滤器linbreaks将包含换行符的长条目转换为浏览器能够理解的格式,一面显示为一个不间断的文本块。
d.将显示所有主题的页面(http://localhost:8000/topics)中的每个主题都设置为链接。这里使用模板标签url根据learning_logs中名为topic的URL模式来生成核实的链接。这个URL模式要求提供实参topic_id,因此在模板标签url中添加了属性topic.id。修改topics.html 代码如下:
{% 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}}</a>
</li>
{% empty %}
<li>No topics have been added yet.</li>
{% endfor %}
</ul>
{% endblock content %}