开源图书《Python完全自学教程》12.3制作网站

2022-12-09 20:23:00 浏览数 (1)

12.3 制作网站

网站,现在可谓是司空见惯,就连本书作者也有个人网站(www.itdiffer.com),用以向读者提供所编写书籍的参考资料。那么,怎么制作网站?如果从理论上说,这是一个听起来、讲起来都比较复杂的事情。首先要全面了解有关计算机网络的有关知识(推荐阅读《计算机网络》,谢希仁编著,电子工业出版社出版),然后要能够运用多项技术,比如搭建服务器并部署有关程序、创建数据库、编写网站代码(还分前端和后端)、配置网站域名等,甚至还要考虑网站的并发量、安全性。所以,通常制作网站的项目,都是由若干个人组成一个团队协作完成。

不过,随着技术发展,制作网站的技术门槛正在不断降低,很多底层的东西都被“封装”和“模块化”,开发者将更多精力集中在网站的功能上。这就类似于 Python 中的包和模块一样,比如12.2.2 节中使用的 sqlite3 模块,我们不需要了解其内部工作机制,关注点在于用它实现数据库的连接和操作。

Python 生态中,提供了很多制作网站的包——更习惯的说法是Web框架(Web Framework),比如 Web.py 、Tornado 、Flask 、Django 等,不同框架会有各自的特点,很难用“好、坏”这种简单标准来评价——有的人热衷于“二进制”思维,但愿本书读者不要陷入“0/1”口水战。

下面使用 Django 框架,简要演示用它快速制作网站的流程。

Django 的官方网站(https://www.djangoproject.com/)上显示,撰写本节内容时所发布的最新版是 Django 3.2.5 ,此前 Django 有过 2.x 和 1.x 的各个版本。读者在阅读到本书并调试代码的时候,或者阅读其他有关资料时,务必注意版本问题,不同版本之间会有所差异。此外,围绕 Django 框架还有很多第三方插件(亦即 Python 语言的包或模块),它们也有所适用的版本。

其实,在第11章11.5节,已经在虚拟环境中安装了 Django ,下面就启动该虚拟环境,在其中用 Django 框架制作网站。

12.3.1 创建项目

Django 中的项目(Project)可以看做是一个专有名词,后面还有一个与之有关的名词应用(Application)。所谓项目,可以理解为一个网站。

在虚拟目录 myvenv 内,创建一个 Django 项目(要确认已经进入虚拟环境,参阅第11章11.5节),执行如下指令(本节演示中所有操作系统指令,均为 Linux 指令,请使用 Windows 系统的读者注意):

代码语言:javascript复制
(myvenv) myvenv % ls
bin  include  lib  pyvenv.cfg
(myvenv) myvenv % django-admin startproject mysite
(myvenv) myvenv % ls
bin  include  lib  mysite  pyvenv.cfg

指令 django-admin startproject mysite 创建名为 mysite 的项目,执行此指令后,在当前目录中新增了 ./mysite 子目录。这个子目录并非是空的,Django 会默认为其添加如下内容(以下显示此时 ./mysite 的结构):

代码语言:javascript复制
(myvenv) myvenv % tree mysite
mysite
├── manage.py
└── mysite
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

1 directory, 6 files

然后进入到项目的子目录中,执行 manage.py 程序:

代码语言:javascript复制
(myvenv) myvenv % cd mysite
(myvenv) mysite % python manage.py runserver
Watching for file changes with StatReloader
... (省略其他显示信息)
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

这样我们就把一个基于 Django 的网站跑起来了,由提示信息可知:

  • 可以通过 http://127.0.0.1:8000/ 访问本网站;
  • 结束当前服务的方法是按 Ctrl-C 组合键。

打开浏览器,在地址栏中输入 http://127.0.0.1:8000 或者 http://localhost:8000 ,就会看到图12-3-1所示界面。

图12-3-1 网站默认首页

就这样,已经创建了一个非常简单的网站——好像挺容易的呀。

12.3.2 创建应用

项目已经创建好,网站也有了,接下来要实现网站的具体功能。在 Django 中,人们把这些具体的功能称为应用(Application)。

结束图12-3-1所示的服务(按“Ctrl-C”组合键),继续在虚拟目录中执行如下操作:

代码语言:javascript复制
(myvenv) mysite % ls
db.sqlite3 manage.py mysite

与12.3.1节所看到的 ./mysite 目录结构相比较,这里多了一个文件 db.sqlite3 ,这个文件就是12.2.2节所介绍过的 SQLite 数据库文件,Django 默认使用此类型的数据库,本节的浮光掠影地演示中,也使用这个数据库。

在当前目录中,继续执行:

代码语言:javascript复制
(myvenv) mysite % python manage.py startapp book
(myvenv) mysite % ls
book  db.sqlite3 manage.py mysite

指令 python manage.py startapp book 创建一个名为 book 的应用,并在当前目录中以子目录 ./book 的形式表现。这个子目录中也不是空的,默认配置如下:

代码语言:javascript复制
(myvenv) mysite % tree book
book
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│   └── __init__.py
├── models.py
├── tests.py
└── views.py

1 directory, 7 files

如果把应用理解为项目的子集,当应用创建好之后,就需要向项目“汇报”存在此应用了。用 IDE 工具打开项目目录中的 ./mysite/settings.py 文件(如12.3.1节中执行 tree mysite 后的显示的目录结构),找到第 33 行,对 INSTALLED_APPS 的值做如下修改:

代码语言:javascript复制
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'book',    # 增加一个应用
]

如此就完成了应用的配置——不要忘记保存文件。

12.3.3 数据模型类

一般的动态网站(与之对应的是“静态网站”)都有数据库。Django 为了简化开发,让开发者用 Python 语言可以实现一切,于是对数据库操作提供了 ORM 技术,即 Object-Relational Mapping(对象关系映射)。ORM 的作用是在关系型数据库和业务实体对象之间进行映射,这样在操作业务对象时,就不需要再去和复杂的 SQL 语句打交道,只需简单地操作对象的属性和方法。

Django 的 ORM 实现方式就是编写数据模型类,这些类可以写到任何文件中,通常写在每个应用的models.py 文件中。每个数据模型类都是 django.db.models.Model 的子类。应用的名称(小写字母)和数据模型类的名称(小写字母)共同组成一个数据库表的名称。

用 IDE 打开 ./book/models.py 文件,并编写如下数据模型类:

代码语言:javascript复制
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User

class Articles(models.Model):
    title = models.CharField(max_length=300)                     # (1)
    body = models.TextField()
    publish = models.DateTimeField(default=timezone.now)
    class Meta:                                                  # (2)
        ordering = ("-publish",)
    def __str__(self):
        return self.title

Articles 中的 titleauthorbodypublish 是类属性,对应着数据库表的字段。每个类属性的类型(即字段类型)由等号右侧定义——可以理解为类属性的初始值为等号右侧的实例。例如注释(1)中,类属性(字段)title 引用了实例 models.CharField(max_length=300) —— CharField() 类型,并且以参数 max_length=300 的形式说明字段的最大数量。

注释(2)从名称上看貌似 Python 中的元类,但它跟元类不同。在此处,通过 ordering = ("-publish",) 规定了 Articles 实例对象的显示顺序,负号表示按照 publish 字段值的倒序显示。

数据模型类 Articles 编写好之后,再执行如下操作,从而在数据库中创建对应的表结构:

代码语言:javascript复制
# 第一步
(myvenv) mysite % python manage.py makemigrations
Migrations for 'book':
  book/migrations/0001_initial.py
    - Create model Articles

# 第二步
(myvenv) mysite % python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, book, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying book.0001_initial... OK
  Applying sessions.0001_initial... OK

以上操作完成之后,已经在数据库 db.sqlite3 中创建了多个表,其中包括 Articles 类对应的表,图12-3-2显示的是当前已经有的表(其他表都是 Django 默认创建的。图示所用工具仍然是 12.2.2 节用过的软件)

图12-3-2 Article 对应的表结构

12.3.4 发布文章

用 Django 默认的管理功能可以在已经创建的网站上发布文章。要使用此功能,必须先创建超级管理员。

代码语言:javascript复制
(myvenv)  mysite % python manage.py createsuperuser
Username (leave blank to use 'qiwsir'):

注意执行上述指令的位置,在项目目录中,即 manage.py 文件所在位置。输入用户名:

代码语言:javascript复制
(myvenv) mysite % python manage.py createsuperuser
Username (leave blank to use 'qiwsir'): admin
Email address:

再输入邮箱(只要符合邮箱格式就行):

代码语言:javascript复制
(myvenv) mysite % python manage.py createsuperuser
Username (leave blank to use 'qiwsir'): admin
Email address: admin@laoqi.com
Password:

输入密码。注意密码不能太简单,若太简单,系统会给予友好提示。输入一遍之后,再验证一遍,最终出现:

代码语言:javascript复制
(myvenv) qiwsir@qiwsirs-MacBook-Pro mysite % python manage.py createsuperuser
Username (leave blank to use 'qiwsir'): admin
Email address: admin@laoqi.com
Password:
Password (again):
Superuser created successfully.

则超级管理员创建完毕——请牢记用户名和密码。

然后运行服务器。

代码语言:javascript复制
(myvenv) qiwsir@qiwsirs-MacBook-Pro mysite % python manage.py runserver
Watching for file changes with StatReloader
...
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

在浏览器的地址栏中输入 http://127.0.0.1:8000/admin/ ,打开图12-3-3所示的界面。

图12-3-3 管理端登录界面

输入刚才创建的超级管理员的用户名和密码进入系统,如图12-3-4所示。

图12-3-4 管理界面

Groups 和 Users 是 Django 在用户管理应用中默认的两项。单击 Users 会看到当前项目仅有的一个用户 admin,当然可以增加用户,读者一定要试一试。

目前暂不研究用户问题,重点在于发布文章。但是目前还找不到发布文章的地方。

稍安勿躁。用 IDE 打开 ./book/admin.py 文件,输入如下代码,并保存文件。

代码语言:javascript复制
from django.contrib import admin
from .models import Articles

admin.site.register(Articles)

在调试状态下,如果没有新增加的文件,只是修改了原有文件,则不需要重新启动 Django 服务(如果 Django 服务没有启动,请确保启动)。刷新图12-3-4所示的页面,即可看到图12-3-5所示的效果。

图12-3-5 增加对 book 应用的管理

点击“Add”按钮可以添加文章,如图12-3-6所示所示。

图12-3-6 编辑文章

然后点击“SAVE”按钮即可保存此文章。有兴趣可以多发布几篇。

发布文章的目的是给别人看,别人怎么看?接下来解决这个问题。

12.3.5 文章标题列表

根据阅读网站上文章的经验,一般是有一个页面显示文章标题,然后点击标题,呈现该文章的完整内容。本节首先做一个显示标题列表的页面。

用 IDE 打开 ./book/views.py 文件,编写一个能够从数据库中已存储的文章标题的函数——在 Django 中称之为视图函数

代码语言:javascript复制
from django.shortcuts import render
from .models import Articles

def book_title(request):  
    posts = Articles.objects.all()  
    return render(request, "book/titles.html", {"posts":posts})  

函数 book_title() 的参数是 request ,这个参数负责响应所接收到的请求且不能缺少,并总是位于第一的位置。除这个不可或缺的参数外,还可以根据需要在其后增加别的参数。

return 语句中的 render() 函数的作用是将数据渲染到指定模板上(关于模板,见下文内容)。render() 的第一个参数必须是 request ,然后是模板位置和所传送的数据,数据是用类字典的形式传送给模板的。

render() 中出现的 book/titles.html 就是标题列表的前端展示页面——被称为“模板”。在每一个应用中都可以有一个专门的模板目录。进入应用 book 的目录 ./book ,建立一个子目录 ./templates ,名称和位置必须如此,再按照如下方式建立有关文件和子目录。

代码语言:javascript复制
(myvenv) book % tree templates
templates
└── book
    └── titles.html

1 directory, 1 file

templates 目录是 Django 默认的存放本应用所需模板的目录,如果不用自定义的方式指定模板位置,Django 会在运行时自动来这里查找 render() 函数中所指定的模板文件。

然后编写 titles.html 文件的代码,这不是 Python 程序文件,是 HTML 文件,关于它的知识超出本书范畴,读者可以参考有关资料(在此处,可以照抄如下代码)。

代码语言:javascript复制
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    <meta charset="utf-8">
    <meta  name="viewport" content="width=device-width, initial-scale=1">
    <title>my website</title> 
    <!-- Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN Bdg0JdbxYKrThecOKuH5zCYotlSAcp1 c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
</head>

<body>
<div class="container">
<center><h1>老齐的书</h1></center>
    <div class="row">
        <div class="col-md-8">
            <ul>
            {% for post in posts %} 
                <li>{{ post.title }}</li> 
            {% endfor %}
            </ul>
        </div>
        <div class="col-md-4">
            <h2>老齐教室</h2>
            <p>欢迎访问我的网站:www.itdiffer.com</p>
            <p>包括各种学习资料</p>
        </div>
    </div>
</div>
<!-- Bootstrap 核心 JavaScript 文件 -->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
</body>
</html>

视图函数和模板都编写好之后,要想通过网页访问,还需要进行 URL 配置。首先要配置 ./mysite/urls.py ,在这个文件中配置本项目的各个应用。

代码语言:javascript复制
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('book/', include("book.urls"), name='book'),
]

然后在 book 目录中创建文件 urls.py ,并写入如下代码:

代码语言:javascript复制
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.book_title, name="book_title"),
]

重启 Django 服务,在浏览器中输入 http://127.0.0.1:8000/book/ ,会看到图12-3-7所示界面,显示了文章标题。

图12-3-7 显示文章标题的界面

12.3.6 查看文章内容

每一篇文章,在数据库中都会有唯一的 id,因此可以通过文章 id 从数据库中读出该文章,并显示与网页上。

按照用户的操作顺序,在 titles.html 页面中显示的标题应该有超链接,点击该超链接即向服务器请求显示该标题的文章,所以,应该在 titles.html 中显示标题的部分做如下修改。

代码语言:javascript复制
<ul>
    {% for post in posts %} 
        <li><a href="{{post.id}}">{{ post.title }}</a></li> \ 修改
    {% endfor %}
</ul>

而后编辑 ./book/views.py ,增加响应查看文章请求的视图函数 book_article()

代码语言:javascript复制
def book_article(request, article_id):
    article = Articles.objects.get(id=article_id)
    return render(request, 'book/content.html', {"article": article})

视图函数 book_article 的参数除了 request 之外,还有 article_id ,这个参数需要通过前端的请求获得,在后续的 URL 配置中会给予实现。

然后编写展示文章内容的模板文件 ./templates/book/content.html 文件,代码如下:

代码语言:javascript复制
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    <meta charset="utf-8">
    <meta  name="viewport" content="width=device-width, initial-scale=1">
    <title>my website</title> 
    <!-- Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN Bdg0JdbxYKrThecOKuH5zCYotlSAcp1 c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
</head>

<body>
<div class="container">
<center><h1>老齐的书</h1></center>
    <div class="row">
        <div class="col-md-8">
            <center><h2>{{article.title}}</h2></center>
            <center>{{article.publish}}</center>
            <p class="lead">{{article.body}}</p>
        </div>
        <div class="col-md-4">
            <h2>老齐教室</h2>
            <p>欢迎访问我的网站:www.itdiffer.com</p>
            <p>包括各种学习资料</p>
        </div>
    </div>
</div>
<!-- Bootstrap 核心 JavaScript 文件 -->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
</body>
</html>

接着配置 URL,因为还是针对 book 这个应用而言,所以不需要修改 ./mysite/urls.py ,只需要在 ./book/urls.py 文件中增加新的 URL 路径。

代码语言:javascript复制
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.book_title, name="book_title"),
    url(r'(?P<article_id>d)/$', views.book_article, name='book_content'), # new
]

视图函数 book_article(request, article_id) 的参数 article_id ,用于获得 URL 中每篇文章的 id,即 ./book/templates/book/titles.html 文件中的超链接 <a href='{{title.id}}'> 所产生的请求地址中最后的数字,例如 http://127.0.0.1/blog/1/ 。因此,使用 r'(?P<article_id>d)/$' 这种方式,得到该请求的 id 数值并赋值给参数 article_id

现在访问文章标题网页,则所发布的文章已经具有了超级链接(要养成习惯,每次测试效果时,都要查看 Django 是否启动了),点击该标题,即可显示如图12-3-8所示的文章详情页。

图12-3-8 文章详情页

至此,以不求甚解的精神和实践,制作了一个非常简陋的网站——严格地说,是编写了网站源码。要想让这个网站能够成为万维网上的一员,还需要做很多工作,不过那些不是本书要介绍的了,有兴趣的读者可以参考有关资料。

自学建议 制作网站,是软件开发中一个非常普遍的领域,又由于网站的用途和功能、性能要求各异,也出现了各类不同的技术形态,每种技术还会对应专门化的岗位及具有相应专业技能的从业者。

  • 目前常用于网站开发的编程语言包括 PHP、Java、Python、C#、JavaScript等等(此处仅列举常见几种,事实上远不止所列几项)——选用哪一种语言,是一个争论不休的话题。
  • 有的网站,可以用工具软件生成(即使不懂编程语言也能做网站),比如常见的 WordPress(基于 PHP )等。有的网站是静态的(只发布多媒体信息,没有用户注册、登录、用户发布个人信息等功能),比如我的个人网站(www.itdiffer.com )就是利用 GitBook 制作的静态网站。
  • 动态网站(本节所演示的就是一个动态网站)还必须配备数据库,常用的关系型数据库,如 PostgreSQL、MySQL 等。非关系型数据库近年也开始在网站中使用,比如 MongoDB 等。
  • 如果对网站的界面要求比较高,通常要有专门开发前端的工程师和 UI 设计工程师。前端工程师所要掌握的技能包括但不限于 HTML、CSS、JavaScript,以及各种前端开发框架,如 Vue.js 等(前端开发框架发展变化很快,或许过几年 Vue.js 已经成为了历史)。UI 设计工程师通常要会熟练使用各种图片处理工具,并且要有较高的审美和设计能力。
  • 开发好的网站最终要部署到服务器上,目前比较常见的做法是部署到云服务器上,同时要利用诸如 Ngnix 等服务器软件系统,并对网站做各种配置。这也是一项专业技能,特别是在网站的性能、安全性等方面有较高要求的时候。

以上仅仅列出制作和发布网站所涉及到的主要方面,还有很多其他内容,比如网站源码管理、网站测试、网站开发流程、网站功能设计等。总而言之,制作网站是一项综合性很强的系统工程,需要多个技能配合应用(大型项目就把每个技能落实到专业人员上)。 有志于从事 Web 开发的读者,不妨参考上述介绍,在自学完本书内容之后,向着选定的专业技能方向发展。 如果读者愿意以 Django 框架作为 Web 开发的学习起点(这个选择很明智),可以参阅拙作《跟老齐学Python:Django 实战(第二版)》(电子工业出版社)。

0 人点赞