所有网页:【Python】Python编程入门项目3:Django Web应用程序(1)

Django Web应用程序(1)

基于Django 开发一个名为“学习笔记”的项目,这是一个在线的日志系统,能够记录所学习的有关特定主题的知识。

建立项目

要编写一个名为“学习笔记”的Web应用程序,让用户能够记录感兴趣的主题,并在学习每个主题的过程中添加日志条目。“学习笔记”的主页对这个网站进行描述,并邀请用户注册或登录。用户登录后,可以创建新主题、添加新条目以及阅读既有的条目。

建立虚拟环境

要使用Django, 首先需要建立一个虚拟工作环境。虚拟环境是系统的一个位置,可以在其中安装包,并将其与其他Python包隔离。
为项目新建一个目录,命名为learning_log。

python -m venv ll_env

如果不能安装虚拟环境,则执行以下命令:

pip install --user virtualenv

激活虚拟环境执行以下命令:

source ll_env/bin/activate

如果要停止使用虚拟环境,则执行以下命令:

deactivate

安装Django

创建并激活虚拟环境后,执行以下命令安装Django:

pip install Django

在Django中创建项目:

django-admin startproject learning_log .dirlearning_log manage.py ......dir learning_log


注意:命令末尾的句号让新项目使用合适的目录结构,这样开发完成后可轻松地将应用程序部署到服务器。

  • manage.py:这是一个简单的程序,它接受命令并将其交给Django的相关部分去运行。使用这些命令来管理诸如使用数据库和运行服务器等任务。
  • setting.py : 指定Django.py如何与你的系统交互以及如何管理项目。
  • urls.py:告诉Django.py应创建哪些网页来响应浏览器请求。
  • wsgi.py:帮助Django提供它创建的文件,这个文件名是web server gateway interface(Web服务器网关接口)的首字母缩写。

创建数据库

Django将大部分与项目相关的信息都存储在数据库中。
执行以下命令:

python manage.py migrate

执行dir命令,我们发现在目录中多了一个db.sqlite3的文件。SQLite是一种使用单个文件的数据库,是编写简单应用程序的理想选择,因为它让你不用太关注数据库管理的问题。

查看项目

执行如下命令查看是否正确创建了项目:

python manage.py runserver


打开URL链接,如下图所示:

创建应用程序

Django项目由一系列应用程序组成,它们协同工作,让项目成为一个整体。
当前,在前面打开的终端窗口中应该还运行着runserver。再打开一个终端窗口,切换到manage.py所在的目录,运行以下命令:

python manage.py startapp learning_logs

该命令让Django建立创建应用程序所需的基础设施。查看项目目录,发现其中新增了一个learning_logs的文件夹。


进入该文件夹,我们发现其中包含了models.py、admin.py和views.py。这里将使用models.py来定义我们要在应用程序中管理的数据。

定义模型

打开文件models.py,里面包含了如下内容:

from django.db import models# Create your models here.

这为我们导入了模块models,还让我们创建自己的模型。模型告诉Django如何处理应用程序中存储的数据。
在代码层面,模型就是一个类,包含属性和方法。

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

激活模型

要使用模型,必须让Django将应用程序包含到项目中。即settings.py(位于目录learning_log/learning_log中)文件将告诉Django哪些应用程序安装在项目中。

# Application definitionINSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles',]

修改上述内容:

INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # My_apps 'learning_logs',]

接下来,需要让Django修改数据库,使其能够存储与模型Topic相关的信息。在终端中执行如下命令:

python manage.py makemigrations learning_logs

其中makemigrations当Django确定该如何修改数据库,使其能够存储与我们定义的新模型相关联的数据。输出如下:

Migrations for 'learning_logs': learning_logs\migrations\0001_initial.py - Create model Topic

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

(venv) D:\Python_Project\learning_log\venv>python manage.py migrateOperations to perform: Apply all migrations: admin, auth, contenttypes, learning_logs, sessionsRunning migrations: Applying learning_logs.0001_initial... OK

这里的结果表明Django确认为learning_logs应用迁移时一切正常。
每当需要修改“学习笔记”管理的数据时,都采取如下三个步骤:修改models.py;对learning_logs调用makemigrations;让Django迁移项目。

Django管理网站

1. 创建超级用户
Django允许创建具备所有权限的用户——超级用户。执行以下命令在Django中创建超级用户:

python manage.py createsuperuser

这里会提示输入超级用户的用户名、邮箱地址(可以为空)、密码。
2. 向管理网站注册模型
Django自动在管理网站中添加了一些模型,比如User和Group,但是对于我们创建的模型,必须手工进行注册。
打开learning_logs目录中的admin.py文件:

from django.contrib import admin# Register your models here.

为向管理网站注册Topic,输入下面的代码:

from django.contrib import adminfrom learning_logs.models import Topic# Register your models here.admin.site.register(Topic)

先导入我们要注册的模型Topic,然后再使用admin.site.register()让Django通过管理网站管理我们的模型。

现在,使用超级用户账户访问管理网站:访问http://localhost:8000/admin/,输入超级用户的账户和密码。将看到如下内容:


3. 添加主题
单机Topics进入主题网页,它几乎是空的,这是因为我们还没有添加任何主题。单机Add,将看到一个用户添加新主题的表单。在输入狂中输入Chess,单机Save,返回到主题管理页面,其中包括刚创建的主题。

定义模型Entry

要记录学到的象棋与攀岩知识,需要为用户可在学习笔记中添加的条目定义模型。每个条目都与特定的主题相关联,这种关系称为多对一关系,即多个条目可关联到同一个主题。

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.textclass 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] + "..."

Entry也继承了基类Model,第一个属性topic是一个ForeignKey实例。外键是一个数据库术语,它引用了数据库中的另一个记录;这些代码将每个条目关联到特定的主题。每个主题创建时,都给它分配了一个键(或ID)。需要在两项数据之间建立联系时,Django使用与每项信息相关联的键。
属性date_added让我们能够按照创建顺序呈现条目,并在每个条目旁边放置时间戳。
Entry类嵌套了Meta类。Meta存储用于管理模型的额外信息,这里让我们能够设置一个特殊属性,当Django在需要时使用Entries来表示多个条目。

迁移模型Entry

由于添加了一个新模型,需要再次迁移数据库。
整个过程基本为:修改models.py,执行命令python manage.py makemigrations app_name,再执行命令python manage.py migrate。下面为迁移数据库并查看输出:

python manage.py makemigrations learning_logspython manage.py migrate

生成了一个新的迁移文件——0002_entry.py,它告诉Django如何修改数据库,使其能够存储与模型Entry相关的信息。

向管理网站注册Entry

修改admin.py文件

from django.contrib import adminfrom learning_logs.models import Topic,Entry# Register your models here.admin.site.register(Topic)admin.site.register(Entry)

返回浏览器,查看效果

Django shell

输入一些数据后,就可以通过交互式终端会话以编程方式查看这些数据了。这种交互式环境称为Django shell。

(venv) D:\Python_Project\learning_log\venv>python manage.py shellPython 3.7.4 (default, Aug 9 2019, 18:34:13) [MSC v.1915 64 bit (AMD64)] on win32Type "help", "copyright", "credits" or "license" for more information.(InteractiveConsole)>>> from learning_logs.models import Topic>>> Topic.objects.all()<QuerySet [<Topic: Chess>, <Topic: Climbing>]>>>>

使用命令python manage.py shell启动一个Python解释器,导入一个模块learning_logs.models中的模型Topic,然后使用方法Topic.object.all()来获取模型Topic的所有实例;它返回的是一个列表,称为查询集(queryset)。

>>> for topic in topics:... print(topic.id,topic)...1 Chess2 Climbing >>> t = Topic.objects.get(id=1)>>> t.text'Chess'>>> t.date_addeddatetime.datetime(2020, 1, 31, 13, 39, 56, 308565, tzinfo=<UTC>)>>> t.entry_set.all()<QuerySet [<Entry: 国际象棋的第一个阶段是开局,大致是前10步左右。在开局阶段,最好做三件事情:将象和马调出来;努力控制...>, <Entry: 在国际象棋的开局阶段,将象和马调出来很重要。这些棋子威力大,机动性强,在开局阶段扮演着重要角色。...>]>

注意:每次修改模型后,都需要重启shell。要退出shell会话,可按Ctrl+D;如果使用的是Windows系统,应该按Ctrl+Z,在按回车键。

创建网页:学习笔记主页

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

映射URL

用户通过在浏览器中输入URL以及单击连接来请求网页,因此我们需要确定项目需要哪些URL。
打开项目主文件夹learning_log中的文件urls.py,代码如下:

from django.contrib import adminfrom django.urls import pathurlpatterns = [ path('admin/', admin.site.urls),]

这两行导入是为了项目和管理网站URL的函数和模块。这个文件的主体定义了变量urlpatterns。在这个针对整个项目的urls.py文件中,变量urlpatterns包含项目中的应用程序的URL。
我们需要包含learning_logs的URL:

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

#!usr/bin/env python# -*- coding:utf-8 _*-"""@author: Xinzhe@file: urls.py.py@time: 2020/02/01""""""定义learning_logs的URL模式"""from django.conf.urls import urlfrom . import viewsurlpatterns = [ # 主页 url(r'^$',views.index,name='index'),]

导入函数url,是因为需要使用它来将URL映射到视图。导入了模块view,其中的句点让Python从当前的urls.py模块所在的文件夹中导入视图。变量urlpatterns是一个列表,包含可在应用程序learning_logs中请求的网页。
实际的URL模式是一个对函数url()的调用,这个函数接收三个参数:第一个是一个正则表达式,Django在urlpatterns中查找与请求的URL字符串匹配的正则表达式,因此正则表达式定义了Django可查找的模式。

正则表示是r’^$',其中的r让Python将接下来的字符串视为原始字符串,而引号告诉Python正则表示始于和终于何处,尖号让python查看字符串的开头,美元符号让python查看字符串的末尾。总体而言,正则表达式让python查找开头和末尾之间没有任何东西的URL。

URL的第二个实参指定了要调用的视图函数。请求的URL与前述正则表达式匹配时Django将调用views.index。第三个实参将这个URL模式的名称指定为index。

编写视图

视图函数接收请求中的信息,准备好生成网页所需的数据,再将这些数据发送给浏览器。
views.py内容如下:

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')

编写模板

模板定义了网页的结构。模板指定了网页是什么样的,每当网页被请求时,Django将填入相应的数据。
再文件夹learning_logs中新建一个文件夹,并将其命名为templates。在文件夹templates中再新建一个文件夹,并将其命名为learning_logs。在最里面的文件夹learning_logs中新建一个文件并将其命名为index.html。

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Learning_log</title> <p>Learning Log</p> <p>Learning Log helps you keep track of your learning, for any topic you're learning about.</p></head><body></body></html>

现在打开浏览器,进入http://127.0.0.1:8000/
观察到如下图:


出现的问题:


解决办法:
将learning_log/urls.py修改为:

from django.contrib import adminfrom django.conf.urls import include, urlurlpatterns = [ url(r'^admin/', admin.site.urls), url(r'', include(('learning_logs.urls','learning_logs'), namespace='learning_logs')),]

原因:



根据文档的提示,admin.site.urls不用include()函数。书中第二个include()函数没有提供app_namespace,所以会报错。

创建其他页面

我们将创建两个显示数据的网页,其中一个列出所有的主题,另一个显示特定主题的所有条目。

模板继承

编写一个包含通用元素的父模板,并让所有网页都继承这个模板,而不必在每个网页中重复定义这些通用元素。
1. 父模板
创建一个名为base.html的模板,并将其存储在index.html所在的目录中。

<p> <a href="{% url 'learning_logs:index' %}">Learning Log</a></p>{% block content %}{% endblock content %}

其中, learning_logs是一个命名空间,而index是该命名空间中一个名称独特的URL模式。

子模板并非必须定义父模板中的每个块,因此在父模板中,可以使用任意多个块来预留空间,而子模板可根据需要定义相应数量的块。
修改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 %}

显示所有主题的页面

所有主题页面显示用户创建的所有主题,它是第一个需要使用数据的页面
1. URL模式
定义显示所有主题的页面URL。通常使用一个简单的URL片段来指出网页显示的信息。
修改learning_logs/urls.py:

"""定义learning_logs的URL模式"""from django.conf.urls import urlfrom . import viewsurlpatterns = [ # 主页 url(r'^$', views.index, name='index'), # 显示所有的主题 url(r'^topics/$', views.topics, name='topics'),]

2. 视图
在views.py中添加代码:

from django.shortcuts import renderfrom .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)

3. 模板
显示所有主题的页面接受字典context,以便能够使用topics()提供的数据。创建一个名为topics.html的文件,并存储到index.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 context %}

在模板中必须使用{% endfor %}标签来显式地指出其结束位置。
在循环中,将每个主题转换为一个项目列表。要在模板中打印变量,需要将变量名用双花括号括起来。
模板标签{% empty %}告诉Django在列表topics为空时该怎么办:这里为打印一条消息,告诉用户没有添加任何主题。

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

<p> <a href="{% url 'learning_logs:index' %}">Learning Log</a> - <a href="{% url 'learning_logs:topics' %}">Topics</a></p>{% block content %}{% endblock content %}

刷新页面

显示特定主题的页面

显示该主题的名称及该主题的所有条目。同样地,将定义一个新的URL模式,编写一个视图并创建一个模板。还将修改显示所有主题的网页,让每个项目列表项都是一个链接,单机它将显示相应主题的所有条目。
1. URL模式
显示特定主题的页面的URL模式与前面的所有URL模式稍有不同,因为它将使用主题的id属性来指出请求的是哪个主题。修改learning_logs/urls.py文件

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'),]

这里/(?P<topic_id>\d+)/表示与包含在两个斜杠内的整数匹配,并将这个整数存储在一个名为topic_id的实参中。表达式两边的括号捕获URL中的值;P<topic_id>将匹配的值存储到topic_id中。
发现URL与这个模式匹配时,Django将调用视图函数topic(),并将存储在topic_id中的值作为实参传递给它。
2. 视图
函数topic()需要从数据库中获取指定的主题以及与之相关联的所有条目。
在views.py中添加如下内容:

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)

3. 模板
这个模板需要显示主题的名称和条目的内容。创建topic.html文件

{% 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.text|linebreaks }}</p> </li> {% empty %} <li> There are no entries for this topic yes. </li> {% endfor %}</ul>{% endblock content %}

在Django模板中,竖线|表示模板过滤器——对模板变量的值进行修改的函数。过滤器linebreaks将包含换行符的长条目转换为浏览器能够理解的格式,以免显示为一个不间断的文本块。
4. 将显示所有主题的页面中的每个主题都设置为链接
修改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 %}

刷新显示所有主题的页面,如http://127.0.0.1:8000/topics/1/:

参考资料:

《Python编程从入门到实践》

相关推荐

相关文章