1.Django入门
- 准备
Django是一个Web框架,一套用于帮助开发交互式网站的工具,Django能够响应网页请求,还能让你更轻松地读写数据库,管理用户等
建立项目时,首先以规范的方式对项目进行描述,再建立虚拟环境,以便在其中创建项目
通过编写一个名为"学习笔记"的Web应用程序进行学习 - 建立虚拟环境
要使用Django,首先需要建立一个虚拟工作环境,虚拟环境时系统的一个位置,可以在其中安装包,并将其与其他Python包隔离(将项目的库与其他项目分离是有益的)
为项目新建一个目录,将其命名为learning_log,切换到这个目录,并创建一个虚拟环境
MacBook-Pro:learning_log yangdongxing$ python3 -m venv ll_env
MacBook-Pro:learning_log yangdongxing$
运行模块venv,创建一个名为ll_env的虚拟环境
如果python版本比较早,安装virtualenv包
$ pip install --user virtualenv
使用virtualenv创建虚拟环境
learning_log$ virtualenv ll_env
New python executable in ll_env/bin/python Installing setuptools, pip...done. learning_log$
- 激活虚拟环境
建立虚拟环境后,使用下面的命令激活
MacBook-Pro:learning_log yangdongxing$ source ll_env/bin/activate
(ll_env) MacBook-Pro:learning_log yangdongxing$
这个命令运行ll_env/bin中的脚本activate。环境处于活动状态时,环境名将包含在括号内,此时,可以在环境中安装包,并使用已安装的包,在ll_envz中安装的包仅在该环境处于活动状态时才可用
Windows中使用以下命令激活
ll_env\Scripts\activate(不包含source)
使用命令deactivate停止使用虚拟环境
(ll_env) MacBook-Pro:learning_log yangdongxing$ deactivate
MacBook-Pro:learning_log yangdongxing$
- 安装Django
创建并激活虚拟环境后,就可以安装Django了
MacBook-Pro:learning_log yangdongxing$ source ll_env/bin/activate
(ll_env) MacBook-Pro:learning_log yangdongxing$ pip3 install Django
Collecting Django
Downloading https://files.pythonhosted.org/packages/23/91/2245462e57798e9251de87c88b2b8f996d10ddcb68206a8a020561ef7bd3/Django-2.0.5-py3-none-any.whl (7.1MB)
100% |████████████████████████████████| 7.1MB 36kB/s
Collecting pytz (from Django)
Retrying (Retry(total=4, connect=None, read=None, redirect=None)) after connection broken by 'ProtocolError('Connection aborted.', ConnectionResetError(54, 'Connection reset by peer'))': /simple/pytz/
Using cached https://files.pythonhosted.org/packages/dc/83/15f7833b70d3e067ca91467ca245bae0f6fe56ddc7451aa0dc5606b120f2/pytz-2018.4-py2.py3-none-any.whl
Installing collected packages: pytz, Django
Successfully installed Django-2.0.5 pytz-2018.4
You are using pip version 9.0.1, however version 10.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
(ll_env) MacBook-Pro:learning_log yangdongxing$
- 在Django中创建项目
(ll_env) MacBook-Pro:learning_log yangdongxing$ django-admin.py startproject learning_log .
(ll_env) MacBook-Pro:learning_log yangdongxing$ ls
learning_log ll_env manage.py
(ll_env) MacBook-Pro:learning_log yangdongxing$ ls learning_log
__init__.py settings.py urls.py wsgi.py
新建项目(django-admin.py startproject learning_log .)创建了名为learning_log的项目。末尾又一个句点,是让新项目使用合适的目录结构,这样开发玩后可轻松的将应用程序部署到服务器
句点不能忘,忘记了这个句点, 就将创建的文件和文件夹删除(ll_env除外),再重新运行这个命令。
Django新建了一个名为 learning_log的目录。它还创建了一个名为manage.py的文件,这是一个简单的程序,它接受命令 并将其交给Django的相关部分去运行。我们将使用这些命令来管理诸如使用数据库和运行服务器 等任务。
目录learning_log包含4个文件,其中最重要的是settings.py、urls.py和wsgi.py。文件 settings.py指定Django如何与你的系统交互以及如何管理项目。在开发项目的过程中,我们将修 改其中一些设置,并添加一些设置。文件urls.py告诉Django应创建哪些网页来响应浏览器请求。 文件wsgi.py帮助Django提供它创建的文件,这个文件名是web server gateway interface(Web服务 器网关接口)的首字母缩写。
- 创建数据库
Django将大部分与项目相关的信息都存储在数据库中,因此需要创建一个供Django使用的数据库
(ll_env) yangdongxingdeMacBook-Pro:learning_log yangdongxing$ python3 manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, 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 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 sessions.0001_initial... OK
(ll_env) yangdongxingdeMacBook-Pro:learning_log yangdongxing$ ls
db.sqlite3 learning_log ll_env manage.py
将修改数据库成为迁移数据库,首次执行命令migrate时,将让Django确保数据库与项目的当前状态匹配。
- 查看项目
使用命令runserver核实Django是否正确地创建了项目
(ll_env) yangdongxingdeMacBook-Pro:learning_log yangdongxing$ python manage.py runserver
Performing system checks...
System check identified no issues (0 silenced).
May 03, 2018 - 00:24:15
Django version 2.0.5, using settings 'learning_log.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Django启动了一个服务器,可以查看系统中地项目,浏览器打开http://localhost:8000/可以查看Django生成的网页
关闭服务器,使用control+C或Ctrl+C
如果出现错误信息“That port is already in use”(指定端口已被占用),执行命令 manage.py runserver 8001,让Django使用另一个端口,如果端口依然不可用,使用8002,8003一次增大
2.创建应用程序
Django项目是由一系列应用程序组成,协同工作,让项目成为一个整体,目前只创建了一个应用程序,它将完成项目大部分工作。
当前窗口运行着runserver,再打开一个终端窗口,切换到manage.py所在地目录,激活该虚拟环境,再执行命令startapp
MacBook-Pro:learning_log yangdongxing$ source ll_env/bin/activate
(ll_env) MacBook-Pro:learning_log yangdongxing$ python manage.py startapp learning_logs
(ll_env) MacBook-Pro:learning_log yangdongxing$ ls
db.sqlite3 learning_log learning_logs ll_env manage.py
(ll_env) MacBook-Pro:learning_log yangdongxing$ ls learning_logs/
__init__.py apps.py models.py views.py
admin.py migrations tests.py
(ll_env) MacBook-Pro:learning_log yangdongxing$
startapp appname命令让Django建立创建应用程序所需的基础设施,想再再项目目录下多了个learning_logs文件夹,打开这个文件夹,创建了多个文件,使用models.py来定义我们要再应用程序中管理的数据
- 定义模型
打开文件models.py,查看文件中的内容
from django.db import models
# Create your models here.
models.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
属性CharFiled(由字符串或文本组成的数据,需要存储少量的文本,必须告诉Django该在数据库中预留多少空间,这里max_length设置成来200(即200个字符))
属性date_added是一个DateTimeFiled(记录日期和时间的数据,传递了实参auto_add_now= True,每当用户创建新主题时,都让Django将这个属性自动设置成当前的日期和时间)
在https://docs.djangoproject.com/en/1.8/ref/models/fields/中查看模型中使用的各种字段
Django调用str()来显示模型的简单表示,这里返回存储在属性text中的字符串(python2.7中,使用的方法是unicode())
- 激活模型
使用模型,必须让Django将应用程序包含到项目中,打开learning/learning_log中的settings.py,查看那些应用程序安装在项目中
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
这是一个元组,告诉Django项目是由那些应用程序组成的,将前面创建的应用程序添加到这个元组中
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
#我的应用程序
'learning_logs',
]
接下来,让Django修改数据库,使其能够存储与模型Topic相关的信息
(ll_env) MacBook-Pro:learning_log yangdongxing$ python manage.py makemigrations learning_logs
Migrations for 'learning_logs':
learning_logs/migrations/0001_initial.py
- Create model Topic
(ll_env) MacBook-Pro:learning_log yangdongxing$
命令makemigrations让Django确定该如何修改数据库,使其能够存储与我们定义的新模型相 关联的数据。输出表明Django创建了一个名为0001_initial.py的迁移文件,这个文件将在数据库中 为模型Topic创建一个表。
应用上面的迁移,让Django修改数据库
(ll_env) MacBook-Pro:learning_log yangdongxing$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
Running migrations:
Applying learning_logs.0001_initial... OK
最后的OK表明,Django确认为learning_logs应用迁移时一切正常
每当修改管理的数据时,都采用下面三个步骤:修改models.py;对learning_logs调用makemigrations;让Django迁移项目
3.Django管理网站
- 创建超级用户(具备所有权限的用户)
(ll_env) MacBook-Pro:learning_log yangdongxing$ python manage.py createsuperuser
Username (leave blank to use 'yangdongxing'): ll_admin
Email address:
Password:
Password (again):
This password is too short. It must contain at least 8 characters.
This password is too common.
This password is entirely numeric.
Password:
Password (again):
Superuser created successfully.
(ll_env) MacBook-Pro:learning_log yangdongxing$
用户名ll_admin
Django并不存储输入的密码,而存储从该密码派生出来的一个字符串——散列值。每当你输入密码时,Django都计算其散列值,并将结果与存储的散列值进行比较
- 向管理网站注册模型
Django自动在管理网站中添加了一些模型,如User和Group,但对于创建的模型,必须手工进行注册,在创建应用程序learning_logs时,Django在models.py所在的目录中创建了一个名为admin.py的文件
from django.contrib import admin
# Register your models here.
向管理网站注册Topic
from django.contrib import admin
from learning_logs.models import Topic
# Register your models here.
admin.site.register(Topic)
访问http://localhost:8000/admin/
输入刚才创建的超级用户的用户名和密码
在这个网页中,能够添加和修改用户和用户组,还可以管理与刚才定义的模型Topic相关的数据
添加主题
单机Topic进入主题网页,还没有添加任何主题
点击Add,在Text属性输入框输入Chess,保存(save)
在创建一个RockClimbing主题
- 定义模型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.text
class Entry(models.Model):
"""学到的有关某个主题的具体知识"""
#topic = models.ForeignKey(Topic)
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]+"..."
书上写的是topic = models.ForeignKey(Topic),报错init() missing 1 required positional argument: 'on_delete' ,原因是,Django 高版本中,需要写一个参数topic = models.ForeignKey(Topic,on_delete=models.CASCADE)
第一个属性topic是一个ForeignKey实例。外键是一个数据库术语,它引用了数据库中的另一条记录;这些代码将每个条目关联到特定的主题。每个主题创建时,都给它分配了一个键(或ID)。需要在两项数据之间建立联系时, Django使用与每项信息相关联的键。稍后我们将根据这些联系获取与特定主题相关联的所有条目
text属性是TextField实例,这种字段不需要长度限制
在Entry类中嵌套了Meta类,Meta存储用于管理模型的额外信息,设置一个特殊属性,让Django在需要时使用Entries来表示多个条目。如果没有这个类, Django将使用Entrys来表示多个条目
方法str()告诉Django,呈现条目时应显示哪些信息。由于条目包含的文本可能很长,让Django只显示text的前50个字符。添加了一个省略号,指出显示的并非整个条目。
- 迁移模型ENtry
命令同上Topic
python manage.py makemigrations learning_logs
- 向管理网站注册Entry
命令同上,修改admin.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)
刷新http://localhost/admin/,进入Entries,点击Add,看到一个下拉列表,能够选择要为哪个主题创建条目,还有一个用于输入条目的文本框。从下拉列表中选择Chess,并添加一个条目
再添加一个
- Django shell
输入一些数据后,就可通过交互式终端会话以编程方式查看这些数据了。这种交互式环境称 为Django shell,可以用来测试项目和排除其故障
(ll_env) MacBook-Pro:learning_log yangdongxing$ python manage.py shell
Python 3.6.3 (v3.6.3:2c5fed86e0, Oct 3 2017, 00:32:08)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from learning_logs.models import Topic
>>> Top.objects.all()
Traceback (most recent call last):
File "<console>", line 1, in <module>
NameError: name 'Top' is not defined
>>> Topic.objects.all()
<QuerySet [<Topic: Chess>, <Topic: Rock Climbing>]>
>>>
遍历查询集,查看分配给每个主题对象的ID
>>> topics = Topic.objects.all()
>>> for topic in topics:
... print(topic.id,topic)
...
1 Chess
2 Rock Climbing
>>>
直到对象ID后,就可以获取该对象并查看其任何属性
>>> t = Topic.objects.get(id=1)
>>> t.text
'Chess'
>>> t.date_added
datetime.datetime(2018, 5, 3, 4, 52, 5, 942154, tzinfo=<UTC>)
>>>
查看与主题关联的条目
>>> t.entry_set.all()
<QuerySet [<Entry: The opening is the first part of the game, roughly...>, <Entry: In the opening phase of the game, it’s important t...>]>
>>>
每次修改模型后,都要重启shell,这样才能看到修改效果,退出shell会话,使用control+D
4. 创建网页,学习笔记主页
使用Django创建网页的过程通常分为三个阶段:定义URL,编写视图和编写模版
- 映射URL
用户通过在浏览器中输入URL以及单击链接来请求网页,因此需要确定项目需要哪些 URL。主页的URL最重要,它是用户用来访问项目的基础URL。当前,基础URL(http://localhost:8000/)返回默认的Django网站,让我们知道正确地建立了项目。接下来将修改这一点,将这个基础URL映射到“学习笔记”的主页。
打开项目主文件夹learning_log中的文件urls.py
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
变量urlpatterns包含项目中的应用程序的URL。包含模块admin.site.urls,该模块定义了可在管理网站中请求的所有 URL。
将learning_logs的URL添加进去
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('learning_logs.urls', namespace='learning_logs')),
]
在learning_logs下新建urls.py
"""定义learning_logs的URL模式"""
from django.conf.urls import url
from . import views
app_name='learning_logs'
urlpatterns = [
# 主页
url(r'^$', views.index, name='index'), ]
书上没有app_name='learning_logs' ,加会报错Specifying a namespace in include() without providing an app_name 'django.co
- 编写视图,打开learning_logs中的文件views.py
from django.shortcuts import render
# Create your views here.
为主页编写视图
from django.shortcuts import render
# Create your views here.
def index(request):
"""学习笔记的主页"""
return render(request,'learning_logs/index.html')
pass
- 创建其他网页
创建俩个显示数据的网页,一个列出所有的主题,另一个显示特定主题的所有条目
模版继承
首先来创建一个名为base.html的模板,并将其存储在index.html所在的目录中。这个文件 包含所有页面都有的元素;其他的模板都继承base.html
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a>
</p>>
{% block content %}{% endblock content %}
子模版
{% extends "learning_logs/base.html" %}
{% block content %}
{% endblock content %}
子模板的第一行必须包含标签{% extends %},让Django知道它继 承了哪个父模板。文件base.html位于文件夹learning_logs中,因此父模板路径中包含learning_logs。 这行代码导入模板base.html的所有内容,让index.html能够指定要在content块预留的空间中添加 的内容。
插入了一个名为content的{% block %}标签,以定义content块。不是从父模板 继承的内容都包含在content块中,在这里是一个描述项目“学习笔记”的段落
使用标签{% endblock content %}指出了内容定义的结束位置。
在子模板中,只需包含当前网页特有的内容。这不仅简化 了每个模板,还使得网站修改起来容易得多。要修改很多网页都包含的元素,只需在父模板中修 改该元素
在大型项目中,通常有一个用于整个网站的父模板——base.html,且网站的每个主要部 2
分都有一个父模板。每个部分的父模板都继承base.html,而网站的每个网页都继承相应 部分的父模板
- 显示所有主题的页面
URL模式
"""定义learning_logs的URL模式"""
from django.conf.urls import url
from . import views
app_name='learning_logs'
urlpatterns = [
# 主页
url(r'^$', views.index, name='index'),
# 显示所有的主题
url(r'^topics/$', views.topics, name='topics'),
]
视图
from django.shortcuts import render
from .models import Topic
# Create your views here.
def index(request):
"""学习笔记的主页"""
return render(request,'learning_logs/index.html')
passxxxxx
def topics(request):
"""显示所有的主题"""
topics = Topic.objects.order_by('date_added')
context = {'topics':topics}
return render(request,'learning_logs/topics.html',context)
模版(新建topics.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 %}
修改base.html,使其包含到显示所有主题的页面的链接
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a>
<a href="{% url 'learning_logs:topics' %}">Topics</a>
</p>>
{% block content %}{% endblock content %}
显示特定主题的页面
URL模式,要查看主题Chess(其id为1)的详细页面,URL将为http://localhost:8000/topics/1/
"""定义learning_logs的URL模式"""
from django.conf.urls import url
from . import views
app_name='learning_logs'
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'),
]
视图
from django.shortcuts import render
from .models import Topic
# Create your views here.
def index(request):
"""学习笔记的主页"""
return render(request,'learning_logs/index.html')
passxxxxx
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)
这个函数接受正则表达式(?P<topic_id>\d+)捕获的值,并将其存储到topic_id中
模版
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 %}
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 yet.
</li>
{% endfor %}
</ul>
{% endblock content %}