本章内容来自书籍,记录下来仅方便复习,如有侵权,请联系作者删除。
+++python学习笔记+++
学习如何使用Django(http://djangoproject.com)
开发“学习笔记”(Learning Log)项目,这是一个在线系统日志。
Django是一个Web框架——一套用于开发交互式网站的工具,能够响应网页请求,读写数据,管理用户等。
建立项目时,首先需要以规范的方式对项目进行描述,再建立虚拟环境,以便在其中创建项目。
1. 指定规范
阐述项目功能,外观,用户界面。
编写一个名为“学习笔记”的Web应用程序,让用户记录主题,在主题中增加日志条目。邀请用户注册或登录,创建新主题,添加新条目,阅读既有的条目。
2. 建立虚拟环境
虚拟环境是系统的一个位置,可以在其中安装包,并将其与其他的Python包隔离。将项目的库与其他项目分离是有益的。
为项目新建一个目录,名为learning_log,在终端切换到该目录,并创建一个虚拟环境。这里运行了venv模块,并使用它来创建一个名为ll_env的虚拟环境。
创建命令:leaning_log>python -m venv ll_env
3. 安装virtualenv
如果不能使用模块venv,我们可以安装virtualenv包。
安装命令:pip install virtualenv
…linux…(省略)
4. 激活虚拟环境
建立虚拟环境后,需要使用下面的命令来激活它
Windows激活命令:ll_env\Scripts\activate
要停止使用虚拟环境,可执行命令deactivate
5. 安装Django
在虚拟环境中安装
(ll_env)learning_log> pip install Django
Django仅在虚拟环境处于活动状态时可用。
6. 在Django中创建项目
(ll_env)learning_log> django-admin.py startproject learning_log .
命令末尾的句点让新项目使用合适的目录结构。如果忘记句点,将创建的文件和文件夹删除(ll_env除外),再重新运行这个命令。
(ll_env)learning_log\learning_log>dir
(查看目录)
settings.py:指定Django如何与你的系统交互以及如何管理项目;
urls.py:告诉Django应创建哪些网页来响应浏览器请求;
wsgi.py:帮助Django提供它创建的文件,是web server gateway interface(Web服务器网关接口)首字母的缩写。
7. 创建数据库
Django将大部分与项目相关的信息都存储在数据库中,因此我们要创建一个供Django使用的数据库。
创建数据库,在虚拟环境下执行以下命令
(ll_env)learning_log> python manage.py migrate
(ll_env)learning_log> dir
db.sqlite3 learning_log ll_env manage.py
我们将修改数据库称为迁移数据库,首次执行命令migrate时,将让Django确保数据库与项目的当前状态匹配。
8. 查看项目
核实Django是否正确地创建了项目,可执行命令runserver
(ll_env)learning_log> python manage.py runserver
运行结果:
(ll_env) D:\django\learning_log>python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
(1)System check identified no issues (0 silenced).
October 07, 2019 - 21:07:47
(2)Django version 2.2.6, using settings 'learning_log.settings'
(3)Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
(1)Django通过检查确认地创建了项目
(2)Django的版本,当前使用的设置文件的名称
(3)指出项目的URL,端口号
打开浏览器,输入url和端口号,可以正常访问。
如果想要关闭服务器,按住Ctrl+C即可。
如果要切换端口号,可以在runserver命令后添加端口号
端口号修改为8001:Python manage.py runserver 8001
当前终端窗口应该还运行着runserver
再打开一个终端端口,切换到manage.py所在的目录,然后:
激活该虚拟环境:ll_env\Scripts\activate
执行命令startapp:python manage.py startapp learning_logs
查看项目目录,可以看到其中新增了一个文件夹,learning_logs,其中最重要的文件是,models.py, admin.py, views.py
models.py:定义我们要在应用程序中管理的数据
admin.py:
views.py:
1. 定义模型
打开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
(1)属性text
是一个CharField——由字符或文本组成的数据。必须使用max_length告诉Django在数据库中预留多少空间。
(2)属性date_added
是一个DateTimeField——记录日期和时间的数据。传递实参auto_add_now=True,当用户创建新主题时,让Django将这个属性设置成当前日期和时间。
(3)方法__str__()
,显示模型的简单表示,这里返回噢存储在text中的字符串。
2. 激活模型
如果要使用模型,首先让Django将应用程序包含到项目中。为此,打开learning_log目录下的settings.py,找到列表INSTALLED_APPS,添加我的应用程序learning_logs
settings.py
--snip--
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
#我的应用程序
'learning_logs',
]
--snip--
python manage.py makemigrations learning_logs
运行结果:
(ll_env) D:\django\learning_log>python manage.py makemigrations learning_logs
Migrations for 'learning_logs':
learning_logs\migrations\0001_initial.py
- Create model Topic
makemigrations让Django确定该如何修改数据库,使其能够存储与我们定义的新模型相关联的数据。
python manage.py migrate
运行结果:
(ll_env) D:\django\learning_log>python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
Running migrations:
(1) Applying learning_logs.0001_initial... OK
我们检查(1)处的输出行,在这里Django确认为learning_logs应用迁移时一切正常(OK)。
每当需要修改学习笔记管理的数据时,都采取如下三个步骤:
step1: 修改models.py
step2: 对learning_logs调用makemigrations
python manage.py makemigrations learning_logs
step3: 让Django迁移项目
python manage.py migrate
3. Django管理网站
为应用程序定义模型时,Django提供的管理网站(admin site)让你能够轻松地处理模型。
(1)创建超级用户
Django允许你创建具有所有权限的用户——超级用户。
(ll_env) learning_log> python manage.py createsuperuser
运行结果:
(ll_env) D:\django\learning_log>python manage.py createsuperuser
Username (leave blank to use 'higirl'): ll_admin
Email address:
Password:
Password (again):
Superuser created successfully.
创建超级用户时,需要输入用户名和密码,电子邮件地址可以为空。
(2)向管理网站注册模型
admin.py
from django.contrib import admin
# Register your models here.
from learning_logs.models import Topic #(code1)
admin.site.register(Topic) #(code2)
我们在(code1)处导入注册模型,在(code2)处让Django通过管理网站管理我们的模型。此时我们可以使用超级账户访问管理网站http://localhost:8000/admin。我们能够添加和修改用户和用户组,管理刚刚定义的模型Topic相关的数据。
(3)添加主题
添加第一个主题,单击Topics进入主题网页,单击Add topic,在添加主题的表单中输入Chess,单击Save,返回到主题管理页面。再创建第二个主题Rock Climbing,单击Save回到主题管理页面,可以看到刚刚添加的两个主题。
4. 定义模型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) #(code1)
text = models.TextField() #(code2)
date_added = models.DateTimeField(auto_now_add=True)
class Meta: #(code3)
verbose_name_plural = 'entries'
def __str__(self): #(code4)
return self.text[:50] + "..."
Entry也继承Django基类Model,分析如下:
(code1):属性topic,是一个ForeignKey实例,外键。将这个条目关联到了主题Topic。
在django2.0后,定义外键和一对一关系的时候需要加on_delete选项,此参数为了避免两个表里的数据不一致问题。
参数说明:
on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五个可选择的值
CASCADE:此值设置,是级联删除。
PROTECT:此值设置,是会报完整性错误。
SET_NULL:此值设置,会把外键设置为null,前提是允许为null。
SET_DEFAULT:此值设置,会把设置为外键的默认值。
SET():此值设置,会调用外面的值,可以是一个函数。
一般情况下使用CASCADE就可以了。
来自:https://www.cnblogs.com/phyger/p/8035253.html
(code2):属性text,是一个TextField实例,不需要长度限制
(code3):属性date_added,让我们能够按创建时间顺序呈现条目
(code4):在Entry类中嵌套Meta类,用于管理模型的额外信息,它让我们能够设置一个特殊属性。
(code5):方法__str__()
告诉Django,呈现条目时应该显示哪些信息,由于条目中包含的文本可能过长,我们让Django只显示text的前50个字符。
5. 迁移模型Entry(条目)
由于我们创建了新模型,因此需要再次迁移数据库。
step2:
(ll_env)learning_log>python manage.py makemigrations learning_logs
运行结果:
(ll_env) D:\django\learning_log>python manage.py makemigrations learning_logs
Migrations for 'learning_logs':
learning_logs\migrations\0002_entry.py #result1
- Create model Entry
result1表示生成新的迁移文件,它告诉Django如何修改数据库,使其能够存储与模型Entry相关的信息。
step3:
(ll_env)learning_log> python manage.py migrate
运行结果:
(ll_env) D:\django\learning_log>python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
Running migrations:
Applying learning_logs.0002_entry... OK #result2
result2表示,执行命令migrate,Django应用了这种迁移且一切顺利。
6. 向管理网站注册Entry
注册模型Entry,修改admin.py
from django.contrib import admin
from learning_logs.models import Topic,Entry
admin.site.register(Topic)
admin.site.register(Entry)
浏览器访问http://localhost:8000/admin/
单击Entries,点击Add链接,下拉列表选择Chess/Rock Climbing。可以往text文本框中添加条目。单击Save表示保存成功。
7. Django shell
输入一些数据后,就可以通过交互式终端会话,以编程的方式查看这些数据。这种交互式环境称为Django shell,是测试项目和排除其故障的理想之地。
示例:
(ll_env)learning_log> python manage.py shell
(ll_env) D:\django\learning_log>python manage.py shell #(code1)
>>> from learning_logs.models import Topic #(code2)
>>> Topic.objects.all() #(code3)
<QuerySet [<Topic: Chess>, <Topic: Rock Climbing>]> #(result1)
(code1):启动一个Python解释器,可使用它来探索存储在项目数据库中的数据。
(code2):导入模块learning_logs.models中的模型Topic
(code3):获取模型Topic的所有实例
(result1):返回一个列表,称为查询集(queryset)
操作查询集:
(1)遍历查询集,查看分配给每个主题对象的ID
>>> topics = Topic.objects.all()
>>> for topic in topics:
... print(topic.id,topic)
...
1 Chess
2 Rock Climbing
(2)通过id获取该对象并查看其任何属性
>>> t = Topic.objects.get(id=1)
>>> t.text
'Chess'
>>> t.date_added
datetime.datetime(2019, 10, 8, 2, 39, 3, 408620, tzinfo=<UTC>)
>>> t.entry_set.all()
<QuerySet [<Entry: The opening is the first part of the games, roughl...>, <Entr
y: In the opening phase of the game, it's important t...>]>
>>>
每次修改模型后,都要重启shell,才能看到修改的效果,要退出shell会话,可按Ctrl+Z,再按回车键。
使用Django创建网页的过程通常分为三个阶段:定义URL,编写视图,编写模板。
1. 映射URL
用户通过在浏览器中输入URL以及单击连接来请求网页,因此我们需要确定项目需要哪些URL。
from django.contrib import admin
from django.urls import path,include #(code1)
urlpatterns = [ #(code2)
path('admin/', admin.site.urls), #(code3)
#添加路径
path('', include(('learning_logs.urls','learning_logs'), namespace='learning_logs')), #(code4)
]
(code1):导入为项目和管理网站管理URL的函数和模块
(code2):定义变量urlpatterns,包含项目中应用程序的URL
(code3):包含模块admin.site.urls,定义了可在管理网站中请求的所有URL
(code4):添加一行代码来包含learning_logs.urls。包含实参namespace=‘learning_log’,与其他项目的URL区分开。
from django.urls import path
from . import views
app_name='learning_logs' #(code1)
urlpatterns = [ #(code2)
path('', views.index, name = 'index'), #(code3)
]
首先导入函数path,将URL映射到视图,让Python从当前的urls.py模块所在的文件夹中导入视图模块views,
(code1):定义列表urlpatterns,包含可在应用程序learning_logs中请求的网页。
(code2):接受三个实参,正则表达式,指定要调用的视图,将这个URL模式的名称指定为index。
2. 编写视图
from django.shortcuts import render #(code1)
# Create your views here.
def index(request): #(code2)
return render(request, 'learning_logs/index.html')
(code1):根据视图提供的数据渲染响应。
(code2):URL请求与我们刚才定义的模式匹配时,Django将在文件views.py中查找函数index(),再将请求对象传递给这个视图函数。这个函数调用render中的代码,传递两个实参:请求对象,一个可用于创建网页的模板。
3. 编写模板
在文件夹learning_logs中新建一个文件夹templates,在文件夹templates中新建一个文件夹命名为learning_logs,在新的文件夹learning_logs中新建文件index.html。这样建立了Django能够明确解读的结构。
结构如下:
learning_logs/
|---templates/
|---learning_logs/
|---index.html
index.html文件如下:
index.html
<h1>Learning Log</h1>
<p>Learning Log helps you keep track of your learning, for any topic you'readonly
learning about.</p>
现在可以通过http://localhost:8000/访问Django网页了。
运行过程:Django接受请求的URL,发现URL与正则表达式模式匹配,因此调用函数views.index(),然后使用index.html包含的模板来渲染网页。这里实现了将URL、视图和模板分离。
扩充学习笔记的项目。创建两个显示数据的网页,其中一个列出所有的主题,另一个显示特定主题的所有条目。对于每个网页,我们都将指定URL模式,编写一个视图函数,并编写一个模板。
1. 模板继承
创建网页时,几乎都有一些所有网页都包含的元素,在这种情况下,可编写一个包含通用元素的父模板,并让每个网页都继承这个模板,而不必在每个网页中重复定义这些通用元素。
(1)父模板
使用模板标签,用大括号和百分号({% %}
)表示,模板标签是一小段代码,生成要在网页中显示的信息。
base.html
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a> #code1
</p>
{
% block content %}{
% endblock content %}
code1:模板标签生成一个URL,该URL与learning_logs/url.py中定义名为index的URL模式匹配。
(2)子模板
index.html
{
% extends "learning_logs/base.html" %} #code1
{
% block content %} #code2
<p>Learning Log helps you keep track of your learning, for any topic you'readonly
learning about.</p>
{
% endblock content %}
code1:子模板的第一行必须包含标签{% extends %},告诉Django继承了那个模板
code2:插入一个名为content的{% block %}标签,定义content模块。不是从父模板继承的内容都包含在content块中。
2. 显示所有主题的页面
urls.py
'''定义learning_logs的URL模式'''
from django.urls import path
from . import views
app_name='learning_logs'
urlpatterns = [
# 主页
path('', views.index, name = 'index'),
# 显示所有的主题
path('topic/',views.topics,name='topics'),
# 特定主题的详细页面(?P\d+) 改为 /
path('topics//' ,views.topic,name='topic')
]
发现URL与这个模式匹配时,Django将调用视图函数topic(),并将存储在topic_id中的值作为实参传递给它。在这个函数中,我们将使用topic_id的值来获取相应的主题。
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)
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> #code1
<p>{
{
entry.text|linebreaks }}</p> #code2
</li>
{
% empty %}
<li>
There are no entries for this topic yet.
</li>
{
% endfor %}
</ul>
{
% endblock content %}
竖线(|
)表示模板过滤器——对模板变量的值进行修改的函数。
code1:过滤器date,时间戳格式化
code2:过滤器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 topic have been added yet.</li>
{
% endfor %}
</ul>
{
% endblock content%}
以下是学习过程中遇到的问题:
(1) 生成数据库表时报错
https://www.cnblogs.com/phyger/p/8035253.html
Django在根据models生成数据库表时报 init() missing 1 required positional argument: ‘on_delete’
在django2.0后,定义外键和一对一关系的时候需要加on_delete选项,此参数为了避免两个表里的数据不一致问题,不然会报错:
解决方法:
引用外键的时候,传递实参on_delete。
herobook=models.ForeignKey(‘BookInfo’,on_delete=models.CASCADE,)
(2)Django中url的正则表达式错误
https://blog.csdn.net/u012041204/article/details/80208949
WARNINGS:?: (2_0.W001) Your URL pattern ‘^KaTeX parse error: Expected group after '^' at position 69: …begins with a '^̲', or ends with…’.
This was likely an oversight when migrating to django.urls.path().
今天在使用Django时遇到上面的警告,虽然只是警告,但是却会导致网站无法访问。这问题是Django新版本改变导致URL中不需要再使用正则表达式了,只需要路径就OK了。
解决方法:
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login,name='login'),
path('',views.index,name='index'), #此处设置为首页,以前写法是'^$',新版本不再使用^、$,只需要''就可以
]
(3)runserver发生错误
https://blog.csdn.net/weixin_40841752/article/details/79335345
django.core.exceptions.ImproperlyConfigured:
Specifying a namespace in include() without providing an app_name is not supported.
Set the app_name attribute in the included module,
or pass a 2-tuple containing the list of patterns and app_name instead.
意思为:
在include方法里面指定namespace却不提供app_name是不允许的。
在包含的模块里设置app_name变量,或者在include方法里面提供app_name参数。
解决方法
方法1:在proj/urls.py中修改
from django.urls import path,include
from app import urls as app_url
urlpatterns = [
path('', include((common_url,'common'), namespace='common')),
]
方法2:在app/urls.py中修改
from django.urls import path
from .views import index
app_name='common'
urlpatterns = [
path('',index,name='index'),
]
(4)endblock找不到
django.template.exceptions.TemplateSyntaxError: Unclosed tag on line 5: ‘block’.
Looking for one of: endblock.
解决方法:调整格式正确{% %},注意括号,百分号中英文格式等。
https://stackoverflow.com/questions/29255433/unclosed-tag-block-looking-for-one-of-endblock
(5) lilyxiaoyy的博客,有挺多文章
http://blog.sina.com.cn/xyy890130
python3 Django显示主题的页面
http://blog.sina.com.cn/s/blog_6436b8ec0102x5mr.html