建立项目

建立项目时,首先需要以规范的方式对项目进行描述,再建立虚拟环境,以便在其中创建项目。

指定规范

完整的规范详细说明了项目的目标,阐述了项目的功能,并讨论了项目的外观和用户界面。与任何良好的项目规划都和商业计划书一样,规范应突出重点,帮助避免项目偏离轨道。这里简单制定以下项目规范:

这里根据《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

Python 入门项目——Django入门_python

也可以下载 Django-3.1.3-py3-none-any.whl 文件安装,下载链接
使用下面命令来安装。

py -m pip install --user .\Django-3.1.3-py3-none-any.whl

验证安装成功:

Python 入门项目——Django入门_python_02

在 Django 中创建项目

在还处于活动的虚拟环境的情况下,执行以下命令来新建一个项目:

django-admin.py startproject learning_log .
learning_log

查看项目结构:

Python 入门项目——Django入门_html_03
这里简单说明一下项目中的各个文件:

settings.pyurls.pywsgi.py

创建数据库

Django 将大部分与项目相关的信息都存储到数据库中,所以我们还需要创建一个供 Django 使用的数据库。为项目 “学习笔记” 创建数据库,继续在虚拟环境下执行下面命令:

py manage.py migrate
migratemanage.py

查看项目

runserver

Python 入门项目——Django入门_python_05
在浏览器中输入这里的 server url:http://127.0.0.1:8000/,显示如下界面:

Python 入门项目——Django入门_python_06

创建应用程序

Django 项目由一系列应用程序组成,它们协同工作,让项目成为一个整体。这里暂时创建一个应用程序,使它完成项目的大部分工作。

当前,在前面打开的终端窗口中应该还运行着 runserver。这里再打开一个终端窗口,执行如下命令:

source 11_env/bin/activeate
py manage.py startapp learning_logs
startapplearning_logsmodels.pyadmin.pyviews.pymodels.pyadmin.pyviews.py

Python 入门项目——Django入门_django_07

定义模型

现在根据 “学习笔记” 项目来思考一下需要涉及的数据。
每位用户都需要创建很多主题,而很多条目斗鱼主题相关联,这些条目又都是以文本方式显示。此外,我们还需要存储每个条目的时间戳,以方便告诉用户这些条目都是什么时候创建的。

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

Python 入门项目——Django入门_应用程序_08

makemigrations0001_initial.pyTopic

下面来应用这种迁移,让 Django 帮我修改数据库:

$ py.exe manage.py migrate   
migrate

每当需要修改项目管理的数据时,都要采用以下三个步骤:

models.pylearning_logsmakemigrations

Django 管理网站

Topic
Web
$ python manage.py createsuperuser

Python 入门项目——Django入门_python_10

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

Python 入门项目——Django入门_django_14

定义模型 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

Python 入门项目——Django入门_模版_15

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 的管理页面,能看到此时已经出现的新添加的模型:

Python 入门项目——Django入门_模版_16
Python 入门项目——Django入门_应用程序_17

Python 入门项目——Django入门_html_18
Python 入门项目——Django入门_django_19

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年通过博士、硕士研究生招...>]>
>>>

Python 入门项目——Django入门_django_20
还可以使用类似遍历列表的方式来查询集:

>>> 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 创建网页的过程通常分为三个阶段:

  1. 定义 URL
  2. 编写视图
  3. 编写模版

首先,必须先定义 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/ ,将看到以下内容:

Python 入门项目——Django入门_模版_21

创建其他网页

指定创建网页的流程后,就可以进行扩充 “学习笔记” 的项目了。接下来将创建两个显示数据的网页,其中一个列出所有的主题,另一个现实特定主题的所有条目。对于每个网页,都将指定 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/

Python 入门项目——Django入门_html_22

Python 入门项目——Django入门_html_23

显示特定主题的页面

接下来,就需要创建一个专注于特定主题的页面——显示该主题的名称和所有条目。流程与之前相同。

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 %}
  1. 完成
    Python 入门项目——Django入门_python_24
    Python 入门项目——Django入门_html_25
小结

在本篇内容中,简单学习了如何使用 Django 框架来创建 web 应用程序,并简单实现了 “学习笔记” 项目。在虚拟环境中安装了 Django ,创建项目并且能够在修改模型后轻松迁移数据库,方便项目的迁移部署。除此之外,还学习了 Django shell 的使用,能在终端通过 Django shell 来轻松查看调试网站的数据及接口调用。

通过本篇的基础,接下来就能够优化网页,实现更为复杂和完美的自定义网站了。