建立项目时,首先需要以规范的方式对项目进行描述,再建立虚拟环境,以便在其中创建项目。
指定规范
完整的规范详细说明了项目的目标,阐述了项目的功能,并讨论了项目的外观和用户界面。与任何良好的项目规划都和商业计划书一样,规范应突出重点,帮助避免项目偏离轨道。这里简单制定以下项目规范:
这里根据《Python编程从入门到实践》一书中的描述。
我们要编写一个名为“学习笔记”的 web 应用程序,让用户能够记录感兴趣的主题,并在学习每个主题的过程中添加日志条目。“学习笔记”的主页对这个网站进行描述,并邀请用户注册或登陆。用户登陆后,就可以创建新主题、添加新条目以及阅读既有的条目。学习新的主题时,记录学到的知识可帮助跟踪和复习这些知识。优秀的应用程序让这个记录过程简单易行。
建立虚拟环境
安装 virtualenv(优先)
venv
pip3 install --user virtualenv
建立虚拟环境
要使用 Django ,首先需要建立一个虚拟工作环境。虚拟环境是系统的一个位置,可以在其中安装包,并将其与其他 Python 包隔离开。将项目的库与其他项目分离是有好处的,并且能够很方便地部署到服务器上。
learning_log
python3 -m venv 11_env #Linux下
py.exe -m venv 11_env #Windows下
激活虚拟环境
建立虚拟环境后,需要使用下面的命令来激活它:
source 11_env/bin/activate # Linux下
11_env\Scripts\activate # Windows下
安装 Django
在虚拟环境下安装 Django:
pip install Django
也可以下载 Django-3.1.3-py3-none-any.whl 文件安装,下载链接
使用下面命令来安装。
py -m pip install --user .\Django-3.1.3-py3-none-any.whl
验证安装成功:
在 Django 中创建项目
在还处于活动的虚拟环境的情况下,执行以下命令来新建一个项目:
django-admin.py startproject learning_log .
learning_log
查看项目结构:
这里简单说明一下项目中的各个文件:
settings.pyurls.pywsgi.py
创建数据库
Django 将大部分与项目相关的信息都存储到数据库中,所以我们还需要创建一个供 Django 使用的数据库。为项目 “学习笔记” 创建数据库,继续在虚拟环境下执行下面命令:
py manage.py migrate
migratemanage.py
查看项目
runserver
在浏览器中输入这里的 server url:http://127.0.0.1:8000/,显示如下界面:
Django 项目由一系列应用程序组成,它们协同工作,让项目成为一个整体。这里暂时创建一个应用程序,使它完成项目的大部分工作。
当前,在前面打开的终端窗口中应该还运行着 runserver。这里再打开一个终端窗口,执行如下命令:
source 11_env/bin/activeate
py manage.py startapp learning_logs
startapplearning_logsmodels.pyadmin.pyviews.pymodels.pyadmin.pyviews.py
定义模型
现在根据 “学习笔记” 项目来思考一下需要涉及的数据。
每位用户都需要创建很多主题,而很多条目斗鱼主题相关联,这些条目又都是以文本方式显示。此外,我们还需要存储每个条目的时间戳,以方便告诉用户这些条目都是什么时候创建的。
models.py
from django.db import models
# Create your models here.
models
from django.db import models
# Create your models here.
class Topic(models.Model):
'''用户学习的主题'''
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
'''返回模型的字符串表示'''
return self.text
textCharFielddate_addedDateTimeFieldauto_now_add=True
__str__()text
激活模型
要使用模型,必须让 Django 将应用程序包含到项目中。为此,打开 settings.py ,下面的片段就是告诉 Django 哪些应用程序要安装到项目中:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
INSTALLED_APPS
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 自定义应用
'learning_logs',
]
learning_logs
$ python manage.py makemigrations learning_logs
makemigrations0001_initial.pyTopic
下面来应用这种迁移,让 Django 帮我修改数据库:
$ py.exe manage.py migrate
migrate
每当需要修改项目管理的数据时,都要采用以下三个步骤:
models.pylearning_logsmakemigrations
Django 管理网站
Topic
Web
$ python manage.py createsuperuser
createsuperuser11_admin
UserGrouplearning_logsmodels.pyadmin.py
from django.contrib import admin
from learning_logs.models import Topic
# Register your models here.
admin.site.register(Topic)
Topicadmin.site.register(Topic)py.exe manage.py runserver
TopicTopicAddChessSave
Rock Climbing
定义模型 Entry
models.py
from django.db import models
# Create your models here.
class Topic(models.Model):
'''用户学习的主题'''
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
'''返回模型的字符串表示'''
return self.text
class Entry(models.Model):
'''学到的有关主题的具体知识'''
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = 'entries'
def __str__(self):
'''返回模型的字符串表示'''
return self.text[:50] + "..."
TopicEntryModeltopicForeignKey
textTextFielddata_added
EntryMetaMetaEntriesEntrys__str__()
迁移模型 Entry
models.pypy.exe manage.py makemigrations 'app_name'
<...\Scripts> py.exe manage.py makemigrations learning_logs Migrations for 'learning_logs':
learning_logs\migrations\0002_entry.py
- Create model Entry
<...\Scripts> py.exe manage.py migrate Operations to perform:
Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
Running migrations:
Applying learning_logs.0002_entry... OKe
0002_entry.pyEntrymigrate
向管理网站注册 Entry
Entryadmin.py
from django.contrib import admin
from learning_logs.models import Topic, Entry
# Register your models here.
admin.site.register(Topic)
admin.site.register(Entry)
回到 Django 的管理页面,能看到此时已经出现的新添加的模型:
Django shell
输入一些数据后,就能过通过交互式终端会话以编程方式查看这些数据了。这种交互式环境称为 Django shell ,是测试项目和排除故障的有效方式。如下:
<...\Scripts> py.exe manage.py shell
Python 3.8.3 (tags/v3.8.3:6f8c832, May 13 2020, 22:37:02) [MSC v.1924 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from learning_logs.models import Topic
>>> Topic.objects.all()
<QuerySet [<Topic: Chess>, <Topic: Rock Climbing>]>
>>> from learning_logs.models import Entry
>>> Entry.objects.all()
<QuerySet [<Entry: 据报道,伊朗国防部称,当地时间27日下午,武装恐怖分子袭击了一辆载有伊朗顶级核科学家穆赫森·法赫里扎...>, <Entry: 据武汉理工大学微信公众号27日晚间发布情况通报,近日,在武汉理工大学2020年通过博士、硕士研究生招...>]>
>>>
还可以使用类似遍历列表的方式来查询集:
>>> topics = Topic.objects.all()
>>> for topic in topics:
... print(topic.id, topic)
...
1 Chess
2 Rock Climbing
>>>
>>> t = Topic.objects.get(id=1)
>>> t.text
'Chess'
>>> t.date_added
datetime.datetime(2020, 11, 27, 15, 22, 28, 573639, tzinfo=<UTC>)
>>> t.entry_set.all()
<QuerySet [<Entry: 据报道,伊朗国防部称,当地时间27日下午,武装恐怖分子袭击了一辆载有伊朗顶级核科学家穆赫森·法赫里扎...>]>
>>>
创建网页:学习笔记主页
使用 Django 创建网页的过程通常分为三个阶段:
- 定义 URL
- 编写视图
- 编写模版
首先,必须先定义 URL 模式。URL 模式描述了 URL 是如何设计的,使得 Django 知道如何将浏览器请求与网站 URL 相匹配,以确定返回哪个网页。
每个 URL 都被映射到特定的视图——视图函数获取并处理网页所需的数据。视图函数通常调用一个模版,模版生成浏览器能够理解的网页。接下来,我们就来创建学习笔记的主页,定义该主页的 URL ,编写视图函数并创建一个简单的模版。
映射 URL
http://localhost:8000/
learning_logurls.py
"""learning_log URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
urlpatternsurls.pyurlpatternsadmin.site.urlslearning_logs
from django.contrib import admin
from django.urls import path
from django.urls import include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('learning_logs.urls')),
]
urls.pylearning_loglearning_logsurls.py
'''定义 learning_logs 的 URL 模式'''
from django.conf.urls import url
from django.urls import path
from . import views
urlpatterns = [
#主页
#url(r'^$', views.index, name='index'),
path('', views.index, name='index'),
]
urls.pyurlviewsurlpatternslearning_logs
url()
url(param1, param2, param3)
# param1 正则表达式,匹配 urlpatterns 中查找和请求的 URL 字符串,
# r'^$'中,
# r 使得Python将接下来的字符串视为原始字符串,引号表示正则表达式开始和结尾,
# `^`符号使得Python能够查看字符串的开头。
# '$'符号则能够使得Python查看字符串结尾。
# 综上所述, r'^$' 仅仅与 http://localhost:8000/ 这个 url 相匹配。
# param2 指定了要调用的视图函数,请求url 与前面的正则表示匹配的时候,Django 会调用 view.index 这个函数
# param3 将这个 URL 模式的名称指定为 index ,能够在代码的其他地方引用它,每当需要提供这个 url 链接时,只需要使用这个名称即可,不需要编写 URL。
编写视图
视图函数接收请求中的信息,准备好生成网页所需的数据,再将这些数据发送给浏览器——这通常是使用定义了网页的模版实现的。
learning_logsview.pypython manage.py startapp
from django.shortcuts import render
# Create your views here.
render
from django.shortcuts import render
# Create your views here.
def index(request):
'''学习笔记的主页'''
return render(request, 'learning_logs/index.html')
views.pyindex()render()render()
编写模版
模版定义了网页的结构。模版指定了网页是什么样的,而每当网页被请求时,Django 将填入对应的数据。模版使得能够访问视图提供的任何数据。我们的主页视图没用提供任何数据,所以对应的模版非常简单。
learning_logstemplateslearning_logslearning_logslearning_logsindex.html
<p>Learning Log</p>
<p>Learning Log helps you keep track of your learning, for any topic you're learning about.</p>
这个内容很简单,标签
标识段落;标签指出锻炼开头位置,
指出段落结束位置。这时候再请求这个项目的基础 URL —— http://localhost:8000/ ,将看到以下内容: 创建其他网页
指定创建网页的流程后,就可以进行扩充 “学习笔记” 的项目了。接下来将创建两个显示数据的网页,其中一个列出所有的主题,另一个现实特定主题的所有条目。对于每个网页,都将指定 URL 模式,编写视图函数及模版。在这么做之前先创建一个父模版,项目中的其他模版都将继承它。
模版继承
创建网站时,几乎都有一些所有网页包含的元素,在这种情况下,可编写一个包含通用元素的父模版,并让每个网页都继承这个模版,而不必在每个网页中重复定义这些通用元素。这种方法能让你专注于开发每个网页的独特方面,还能让修改项目的整体外观容易很多。
base.htmlindex.htmlbase.html
base.html
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a>
</p>
{% block content %}{% endblock content %}
Learning Loglearning_logs/urls.pyindexcontent
index.htmlbase.html
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 %}
contentcontent
显示所有主题的页面
有了高效的网页创建方法,就能专注于另外两个网页了:显示全部主题的网页以及显示特定主题中条目的网页。所有主题页面显示用户创建的所有主题,所以这是一个需要数据的网页。
topicshttp://localhost:8000/topics/learning_logs/urls.py
'''定义 learning_logs 的 URL 模式'''
from django.conf.urls import url
from django.urls import path
from . import views
urlpatterns = [
#主页
#url(r'^$', views.index, name='index'),
path('', views.index, name='index'),
path(r'^topics/$', views.topics, name='topics'),
]
urls.pytopicsviews.topics
topics()views.py
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)
contexttopics()index.htmltopics.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 %}
其中用到的 for 循环格式类似如下:
{% for item in list %}
do something with each item
{% endfor %}
这里,还需要修改父模版,使其包含到显示所有主题的页面链接:
<p>
<a href="{% url 'index' %}">Learning Log</a>
<a href="{% url 'topics' %}">Topics</a>
</p>
{% block content %}{% endblock content %}
http://localhost:8000/topics/
显示特定主题的页面
接下来,就需要创建一个专注于特定主题的页面——显示该主题的名称和所有条目。流程与之前相同。
learning_logs/urls.py
'''定义 learning_logs 的 URL 模式'''
from django.conf.urls import url
from django.urls import path
from . import views
urlpatterns = [
#主页
#url(r'^$', views.index, name='index'),
path('', views.index, name='index'),
path(r'^topics/$', views.topics, name='topics'),
path(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),
]
learning_logs/views.py
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)
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)
topics.htmltopics.html
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics</p>
<ul>
{% for topic in topics %}
<a href="{% url 'topic' topic.id %}">{{ topic }}</a>
{% empty %}
<li>No topics have been added yet.</li>
{% endfor %}
</ul>
{% endblock content %}
topic.html
{% extends "learning_logs/base.html" %}
{% block content %}
<p>Topics</p>
<p>Entries:</p>
<ul>
{% for entry in entries %}
<li>
<p>{{ entry.date_added|date:'M d, Y H:i' }}</p>
<p>{{ entry.text|linebreaks }}</p>
</li>
{% empty %}
<li>
There are no entries for this topic yet.
</li>
{% endfor %}
</ul>
{% endblock content %}
- 完成
在本篇内容中,简单学习了如何使用 Django 框架来创建 web 应用程序,并简单实现了 “学习笔记” 项目。在虚拟环境中安装了 Django ,创建项目并且能够在修改模型后轻松迁移数据库,方便项目的迁移部署。除此之外,还学习了 Django shell 的使用,能在终端通过 Django shell 来轻松查看调试网站的数据及接口调用。
通过本篇的基础,接下来就能够优化网页,实现更为复杂和完美的自定义网站了。