本人系统环境:
WIN10系统
Python 3.9
Django 2.1.5
书本环境:
Python 3.x
Django 1.8.5
基于Django 开发一个名为“学习笔记”的项目,这是一个在线的日志系统,能够记录所学习的有关特定主题的知识。
建立项目
要编写一个名为“学习笔记”的Web应用程序,让用户能够记录感兴趣的主题,并在学习每个主题的过程中添加日志条目。“学习笔记”的主页对这个网站进行描述,并邀请用户注册或登录。用户登录后,可以创建新主题、添加新条目以及阅读既有的条目。
建立虚拟环境
要使用Django, 首先需要建立一个虚拟工作环境。虚拟环境是系统的一个位置,可以在其中安装包,并将其与其他Python包隔离。
为项目新建一个目录,命名为learning_log。
python -m venv ll_env
如果不能安装虚拟环境,则执行以下命令:
pip install --user virtualenv
激活虚拟环境执行以下命令:
ll_env\Scripts\activate
如果要停止使用虚拟环境,则执行以下命令:
deactivate
安装Django
pip install --default-timeout=1000 Django==2.1.5
在Django中创建项目:
django-admin startproject learning_log .
注意:命令末尾的句号让新项目使用合适的目录结构,这样开发完成后可轻松地将应用程序部署到服务器。
- manage.py:这是一个简单的程序,它接受命令并将其交给Django的相关部分去运行。使用这些命令来管理诸如使用数据库和运行服务器等任务。
- setting.py : 指定Django.py如何与你的系统交互以及如何管理项目。
- urls.py:告诉Django.py应创建哪些网页来响应浏览器请求。
- wsgi.py:帮助Django提供它创建的文件,这个文件名是web server gateway interface(Web服务器网关接口)的首字母缩写。
打开PyCharm
创建数据库
Django将大部分与项目相关的信息都存储在数据库中。
执行以下命令:
python manage.py migrate
执行dir命令,我们发现在目录中多了一个db.sqlite3的文件。SQLite是一种使用单个文件的数据库,是编写简单应用程序的理想选择,因为它让你不用太关注数据库管理的问题。
查看项目
通过web服务器确认下Django是否正确创建了项目
python manage.py runserver
创建应用程序
Django项目由一系列应用程序组成,它们协同工作,让项目成为一个整体。
当前,在前面打开的终端窗口中应该还运行着runserver。再打开一个终端窗口,切换到manage.py所在的目录,运行以下命令:
python manage.py startapp learning_logs
该命令让Django建立创建应用程序所需的基础设施。查看项目目录,发现其中新增了一个learning_logs的文件夹。
进入该文件夹,我们发现其中包含了models.py、admin.py和views.py。这里将使用models.py来定义我们要在应用程序中管理的数据。
定义模型
打开文件models.py,里面包含了如下内容:
修改H:\learning_log\learning_logs\model.py
这为我们导入了模块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哪些应用程序安装在项目中。
修改H:\learning_log\learning_log\Settings.py
#我的应用程序
'learning_logs',
接下来,需要让Django修改数据库,使其能够存储与模型Topic相关的信息。在终端中执行如下命令:(创建迁移文件,为模型Topics创建一个表)
python manage.py makemigrations learning_logs
其中makemigrations当Django确定该如何修改数据库,使其能够存储与我们定义的新模型相关联的数据。输出如下:
下面应用这种迁移,让Django替我们修改数据库:(应用迁移,修改数据库)
python manage.py migrate
这里的结果表明Django确认为learning_logs应用迁移时一切正常。
每当需要修改“学习笔记”管理的数据时,都采取如下三个步骤:修改models.py;对learning_logs调用makemigrations;让Django迁移项目。
Django管理网站
创建超级用户账号(管理员账号)
Django允许创建具备所有权限的用户——超级用户。执行以下命令在Django中创建超级用户:
python manage.py createsuperuser
这里会提示输入超级用户的用户名、邮箱地址(可以为空)、密码。
向管理网站注册模型
Django自动在管理网站中添加了一些模型,比如User和Group,但是对于我们创建的模型,必须手工进行注册。
打开learning_logs目录中的admin.py文件,为向管理网站注册Topic,输入下面的代码:
修改H:\learning_log\learning_logs\admin.py
from django.contrib import admin
# Register your models here.
from learning_logs.models import Topic
admin.site.register(Topic)
先导入我们要注册的模型Topic,然后再使用admin.site.register()让Django通过管理网站管理我们的模型。
现在,使用超级用户账户访问管理网站:访问http://localhost:8000/admin/,输入超级用户的账户和密码。将看到如下内容:
如果在浏览器中看到一条消息,支出访问的页面不可用,请确认在终端窗口中运行着Django服务器。如果没有,清激活虚拟环境,并执行命令
python manage.py runserver
http://127.0.0.1:8000/admin/login/?next=/admin/
添加主题Chess和Rock Climbing
定义模型
要记录学到的象棋与攀岩知识,需要为用户可在学习笔记中添加的条目定义模型。每个条目都与特定的主题相关联,这种关系称为多对一关系,即多个条目可关联到同一个主题。
修改H:\learning_log\learning_logs\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
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] + "..."
Entry也继承了基类Model,第一个属性topic是一个ForeignKey实例。外键是一个数据库术语,它引用了数据库中的另一个记录;这些代码将每个条目关联到特定的主题。每个主题创建时,都给它分配了一个键(或ID)。需要在两项数据之间建立联系时,Django使用与每项信息相关联的键。
属性date_added让我们能够按照创建顺序呈现条目,并在每个条目旁边放置时间戳。
Entry类嵌套了Meta类。Meta存储用于管理模型的额外信息,这里让我们能够设置一个特殊属性,当Django在需要时使用Entries来表示多个条目。
迁移模型Entry
创建迁移文件,为模型Entry创建一个表
由于添加了一个新模型,需要再次迁移数据库。
整个过程基本为:修改models.py,执行命令python manage.py makemigrations app_name,再执行命令python manage.py migrate。下面为迁移数据库并查看输出:
python manage.py makemigrations learning_logs
应用迁移,修改数据库
python manage.py migrate
向管理网站注册Entry
from django.contrib import admin
# Register your models here.
from learning_logs.models import Topic,Entry
admin.site.register(Topic)
admin.site.register(Entry)
python manage.py runserver
打开浏览器,输入localhost:8000/admin/,使用管理员账号访问管理网站
The opening is the first part of the game,roughly the first ten moves or so.In the opening, it's a good idea to do three things -- bring out your bishops and knights,try to control the center of the board, and castle your king.
Of course,these are just guidelines.It will be important to learn when to follow these guidelines and when to disregard these suggestions.
In the opening phase of the game, it's important to bring out your bishops and knights.These pieces are powerful and maneuverable enough to play a significant role in the beginning moves of a game.
One of the most important concepts in climbing is to keep your weight on your feet as much as possible.There's a myth that climbers can hang all day on their arms.In reality, good climbers have practiced specific ways of keeping their weight over their feet whenever possible.
Django shell
我们也可以用终端来查看数据
输入一些数据后,就可以通过交互式终端会话以编程方式查看这些数据了。这种交互式环境称为Django shell。
(ll_env) H:\learning_log>python manage.py shell
Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 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>]>
>>>
使用命令python manage.py shell启动一个Python解释器,导入一个模块learning_logs.models中的模型Topic,然后使用方法Topic.object.all()来获取模型Topic的所有实例;它返回的是一个列表,称为查询集(queryset)。
注意:每次修改模型后,都需要重启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 admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
这两行导入是为了项目和管理网站URL的函数和模块。这个文件的主体定义了变量urlpatterns。在这个针对整个项目的urls.py文件中,变量urlpatterns包含项目中的应用程序的URL。
我们需要包含learning_logs的URL:
默认的urls.py包含在文件夹learning_log中,现在需要在文件夹learning_logs中创建另一个urls.py文件:
"""定义learning_logs的URL模式"""
from django.urls import path
from . import views
app_name = 'learning_logs'
urlpatterns = [
# 主页
path('', 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/
观察到如下图:
创建其他页面
我们将创建两个显示数据的网页,其中一个列出所有的主题,另一个显示特定主题的所有条目。
模板继承
编写一个包含通用元素的父模板,并让所有网页都继承这个模板,而不必在每个网页中重复定义这些通用元素。
修改H:\learning_log\learning_logs\templates\learning_logs
1. 父模板
创建一个名为base.html的模板,并将其存储在index.html所在的目录中。
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a>
</p>
{% block content %}{% endblock content %}
其中, learning_logs是一个命名空间,而index是该命名空间中一个名称独特的URL模式。
2.子模块
子模板并非必须定义父模板中的每个块,因此在父模板中,可以使用任意多个块来预留空间,而子模板可根据需要定义相应数量的块。
修改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 %}
显示所有主题的页面
所有主题页面显示用户创建的所有主题,它是第一个需要使用数据的页面
URL模式
定义显示所有主题的页面URL。通常使用一个简单的URL片段来指出网页显示的信息。
修改learning_logs/urls.py:
"""定义learning_logs的URL模式"""
from django.conf.urls import url
from . import views
urlpatterns = [
# 主页
url(r'^$', views.index, name='index'),
# 显示所有的主题
url(r'^topics/$', views.topics, name='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)
模板
显示所有主题的页面接受字典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模式,编写一个视图并创建一个模板。还将修改显示所有主题的网页,让每个项目列表项都是一个链接,单机它将显示相应主题的所有条目。
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中的值作为实参传递给它。
视图
函数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)
模板
这个模板需要显示主题的名称和条目的内容。创建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将包含换行符的长条目转换为浏览器能够理解的格式,以免显示为一个不间断的文本块。
将显示所有主题的页面中的每个主题都设置为链接
修改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/: