Python Django 搭建学习笔记博客系统总结

学习笔记是《Python从入门到实践》书中的一个项目。书中会有一些错误,这里我已经修改过了,在Github上的项目是可以运行的。

项目需求

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

开发环境

  • Django 2.0
  • Python 3.5.2
  • window 10 64位
  • 调试浏览器-Chrome 62.0.3202.89版本
  • 开发工具 Sublime Text 3

Tip: 我这里是在虚拟环境下开发,所以要查看 Django 的版本需要先激活虚拟环境 , 然后输入python -m django --version; 查看Python 版本只需在命令行窗口下输入python即可查看。

项目的开发前准备

创建虚拟环境

新建一个目录用于存放当前“学习笔记”项目的所有文件,在终端下切换到当前目录来创建虚拟环境,创建命令如下:

python -m venv ll_env: 先是运行了venv模块,应使用它来创建了一个名为ll_env的虚拟环境。如果不能使用 venv 模块,那么可以尝试先安装 virtualenv。如果能使用 venv 模块,可以不安装 virtualenv,直接激活虚拟环境.

安装virtualenv

pip install --user virtualenv

激活虚拟环境

建立了虚拟环境需要激活才能使用,所以使用下面的命令来激活它:各个平台可能会不一样,我这里是 window 平台

ll_env\Scriptes\activate, 停止虚拟环境可输入deactivate命令

安装 Django

因为我们是在虚拟环境中开发,所以 Django 也是在虚拟环境中安装,输入如下命令:

pip install Django

Tip:Django 仅在虚拟环境被激活的时候才可用

在 Django 中创建项目

django-admin startproject leaning_log .: 注意别漏了末尾的.否则部署应用程序时可能会遭遇一些配置问题。

使用该命令创建了一个项目:leaning_log

如果忘记了这个句点.,就讲创建的文件和文件夹删除(ll_env除外),再重新运行这个命令。

创建数据库

Django 将大部分的项目相关的信息都存储在数据库中,因此我们需要创建一个共Django使用的数据库。

python manage.py migrate

运行项目

在做完以上内容后就可以运行项目了,但是此时运行项目得到的是 Django 主页

python manage.py sunserver,启动了服务器后,在浏览器中输入localhost:80008000表示端口号。如果没出现错误,应该能看到 Django 的主页。关闭服务器在命令行界面按住ctrl+c即可

有可能会出现端口号被占用,提示“That port is already use ”,可以重新执行命令pythonmanage.py runserver 8001,如果还提示端口被占用,可接着换端口去多次尝试。

创建应用程序

Django 项目是由一系列的应用程序组成,他们协同工作,让项目成为一个整体。当前命令行窗口应该还是运行着服务器的。所以要重新打开一个命令行窗口,并切换到manage.py目录下,激活该虚拟环境,再执行命令 startapp ,命令如下

  • 激活虚拟环境ll_env\Scripts\activate
  • 运行应用程序python manage.py startapp leaning_logs

如果这时候查看项目目录,会发现新创建了一个文件夹leaning_logs,打开该文件夹,里面最重要的文件是models.py,admin.py,views.py,我们将用其中的models.py来定义应用程序中管理的数据。

定义模型 leaning_logs/models.py

leaning_logs文件夹的models.py中创建Topic、Entry模型。代表用户创建的 主题 和 文章

模型就是一个类,包含属性和方法。主题模型中可能会定义外键,用于关联主题模型所对应的其他对象。定义外键的作用是用于确定主题属于哪个用户,需要这么去定义外键 owner = models.ForeignKey(User, "on_delete=models.CASCADE")

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from django.db import models
from django.contrib.auth.models import User

class Topic(models.Model):
"""用户要学习的主题."""
# 在数据库中定义了 text 的所占的空间为 200 个字符
text = models.CharField(max_length=200)
# 在数据库中定义了 date_added 的为当前创建的时间
date_added = models.DateTimeField(auto_now_add=True)
# 外键是用户,可以通过这个外键确定这个主题属于哪个用户
owner = models.ForeignKey(User, "on_delete=models.CASCADE")

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

激活模型 leaning_log/settings.py

创建了模型(应用程序)需要激活,在目录lwaning_log/setting.py下将应用程序包含到项目中.

这里添加了leaning_logsusers, 者两个都是自己创建的应用程序,如何创建应用程序,之前已经介绍过了。

在该文件中还可以添加第三方的应用程序,这里就添加了bootstrap3应用程序,用于美化界面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Application definition

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',

# 第三方应用程序
'bootstrap3',

# 我的应用程序
'leaning_logs',
'users',
]

创建了模型之后需要让 Django 修改数据库,使其能够存储与模型相关的信息,因此需要再终端窗口中执行下面的命令:

  • python manage.py makemigrations leaning_logs
  • python manage.py migrate

当每次修改“学习笔记”管理的数据时,都需要经过如下三个步骤:

  • 修改models.py
  • leaning_logs调用makemigrations
  • 让 Django 迁移项目

Django 管理网站

为应用程序定义模型时,Django 提供的管理网站让你能够轻松的处理模型,网站的管理员才可使用管理网站,普通用户不能使用。

创建超级用户

Django 允许创建具备所有权限的用户—超级用户。

python manage.py createsuperuser, 根据提示输入用户名,邮箱地址,密码,确认密码

Tip:Django 并不存储你输入的密码,存储的是你输入密码的派生出来的一个字符串,所以不用担心你的密码会泄露

向管理网站注册模型 leaning_logs/admin.py

Django 自动在管理网站中添加了一些模型,如 UserGroup,但对于我们创建的模型,必须手动进行注册。

1
2
3
4
5
6
from django.contrib import admin

from leaning_logs.models import Topic, Entry
# 注册模型
admin.site.register(Topic)
admin.site.register(Entry)

在浏览器中输入localhost:8000/admin/,可以看到我们注册的模型了 Django 自动添加的模型。

Django shell

输入一些数据后,就可以通过交互式终端去查看这些数据了,这里的中观交互环境称为 Django shell ,Django shell 是测试项目和排除故障的理想的方式。

  • 进入终端python manage.py shell
  • 通过 python 语法可以查看项目中的数据,例如想查看所有文章,可以这么写:
1
2
3
topics = Topic.objects.all()
for topic int topics:
print(topic.id, topic)
  • 每次修改模型后,需要重启 shell 才能看到修改的效果window下退出 shell 的方法是按下 ctrl+z 再按下回车键

以上准备工作和学习之后,就可创建出我们自己的学习笔记主页了!!

创建网页:主页

使用Django 创建网页的过程通常分为三个阶段:

  • 定义 URL
  • 编写视图
  • 编写模板

映射 URL,leaning_log/urls.py

Django 2. 0 版本可以使用 path 模块替代了 url 模块

先导入相应的模块

1
2
3
4
5
6
7
8
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
path('admin/', admin.site.urls),
path('users/', include('users.urls',namespace='users')),
path(r'', include('leaning_logs.urls',namespace='leaning_logs')),
]

在 leaning_logs 和 user 下创建 urls.py 文件

因为在leaning_log/urls.py 中定义了路径, 所以需要在对应的应用程序下也要创建对应的文件,否则会报错,提示找不不到该文件。

  • 分析每一条 url ,如url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),
  • 开头的r可以让python将接下来的字符串视为原始字符串,不会转义
  • ^表示字符串的开头,末尾的$表示字符串的结束。主要匹配的就是这二者之间的内容
  • ?P<topic_id>将匹配的值存储到 topic_id 中。
  • \d+表示包含在两个斜杠内的任意数字都匹配
  • 第二个参数是 url 对应的视图
  • 第三个参数是 给 url 指定的名称
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
--------------------------leaning_logs/urls.py 的内容如下----------------------------
"""定义leaning_logs的URL模式"""
from django.conf.urls import url
from . import views

app_name='leaning_log'
urlpatterns = [
# 主页 , ^开始匹配之后的内容, $结束匹配之前的内容
url(r'^$', views.index, name='index'),
# 显示所有的主题
url(r'^topics/$', views.topics, name='topics'),
# 特定主题的详细页面, ?P<topic_id>:将匹配的值存储在topic_id中,\d+:匹配任意数字
url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),
# 用于添加新主题的网页
url(r'^new_topic/$', views.new_topic, name='new_topic'),
# 用于添加新条目的页面
url(r'^new_entry/(?P<topic_id>\d+)/$', views.new_entry, name='new_entry'),
# 用于编辑条目的页面
url(r'^edit_entry/(?P<entry_id>\d+)/$', views.edit_entry, name='edit_entry'),
]

-------------------------- user/urls.py 的内容如下-------------------

from django.conf.urls import url
from django.contrib.auth.views import login
from . import views

app_name='leaning_log'
urlpatterns = [
# 登录页面. template_name表示使用的是模板中的登录页面,
url(r'^login/$', login, {'template_name': 'users/login.html'}, name='login'),

# 退出登录.
url(r'^logout/$', views.logout_view, name='logout'),

# 注册页面.
url(r'^register/$', views.register, name='register'),
]

编写视图

仅展示 leaning_logs/views.py,更多的内容可以查看源码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
from django.shortcuts import render
from django.http import HttpResponseRedirect, Http404
from django.urls import reverse
from django.contrib.auth.decorators import login_required
from .models import Topic, Entry
from .forms import TopicForm, EntryForm

def index(request):
"""学习笔记的主页"""
return render(request, 'leaning_logs/index.html')

@login_required
def topics(request):
"""显示所有的主题,login_required:加入登录验证,owner=request.user才能查看主题列表"""
topics = Topic.objects.filter(owner=request.user).order_by('date_added')
# 将结果存在context字典中
context = {'topics':topics}
return render(request, 'leaning_logs/topics.html', context)

@login_required
def topic(request, topic_id):
"""显示单个主题及其所有的条目"""
topic = Topic.objects.get(id=topic_id)
# 确认请求的主题属于当前用户
if topic.owner != request.user:
raise Http404

# -date_added -表示按时间降序显示
entries = topic.entry_set.order_by('-date_added')
context = {'topic':topic, 'entries':entries}
return render(request, 'leaning_logs/topic.html', context)

@login_required
def new_topic(request):
"""添加新主题"""
if request.method != 'POST':
# 未提交数据:创建一个新表单
form = TopicForm()
else:
# POST 提交的数据,对数据进行处理
form =TopicForm(request.POST)
if form.is_valid():
# 先修改主题,再保存到数据库中
new_topic = form.save(commit=False)
# 将当前修改主题的人变为新的话题所有者
new_topic.owner = request.user
# 保存到数据库
new_topic.save()
# 返回主页
return HttpResponseRedirect(reverse('leaning_logs:topics'))

context = {'form':form}
return render(request, 'leaning_logs/new_topic.html', context)

@login_required
def new_entry(request, topic_id):
"""在特定的主题重添加条目"""
topic = Topic.objects.get(id=topic_id)

if request.method != 'POST':
# 未提交数据,创建一个空表单
form = EntryForm()
else:
# POST 提交的数据,对数据进行处理
form = EntryForm(data = request.POST)
if form.is_valid():
new_entry = form.save(commit=False)
new_entry.topic = topic
new_entry.save()
return HttpResponseRedirect(reverse('leaning_logs:topic', args=[topic_id]))
context = {'topic':topic, 'form':form}
return render(request, 'leaning_logs/new_entry.html', context)

@login_required
def edit_entry(request, entry_id):
"""编辑既有的条目"""
entry = Entry.objects.get(id=entry_id)
topic = entry.topic
if topic.owner != request.user:
raise Http404

if request.method != 'POST':
# 初次请求,使用当前条目填充表单
form = EntryForm(instance=entry)
else:
# POST提交的数据,对数据进行处理
form = EntryForm(instance=entry, data=request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('leaning_logs:topic',args=[topic.id]))

context = {'entry':entry, 'topic':topic, 'form':form}
return render(request, 'leaning_logs/edit_entry.html',context)

编写模板

仅写其中的一个模板—leaning_logs/templates/leaning_logs/topic.html,更多内容查看项目。这块主要是 html 的相关知识

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
{% extends 'leaning_logs/base.html' %}

{% block header %}
<h3>{{ topic}}</h3>
{% endblock header %}

{% block content %}

<p>
<a href="{% url 'leaning_logs:new_entry' topic.id %}">添加新的笔记 </a>
</p>
<ul>
{% for entry in entries %}
<div class="panel panel-default">
<div class="panel-heading">
<h4>
{{ entry.date_added|date:'M d, Y H:i' }}
<small>
<a href="{% url 'leaning_logs:edit_entry' entry.id %}">编辑</a>
</small>
</h4>
</div>

<div class="panel-body">
{{ entry.text|linebreaks }}
</div>
<!-- panel -->
</div>

{% empty %}
当前主题下还没有笔记哦~,快去记录你的人生吧!
{% endfor %}
</ul>

{% endblock content %}
  • 用户系统也可以看作一个应用程序,所以和上面的 leaning_logs 是一样的。

总结一下

上面步骤写的有些乱,这里来整理一下用Python实现一个学习笔记需要的大概过程,具体可以查看书籍(书籍中实现有些问题,可以查看我实现提交的项目地址,Leaning_log

  1. 开发工具,开发环境肯定时必须的。
  2. 创建一个虚拟环境—激活虚拟环境—在虚拟环境下安装 Django —– 在 Django 中创建项目—–还需要创建一个数据库用于存储数据—-查看项目(如果成功,这时候显示的是 Django 的欢迎页面)
  3. 创建应用程序 —- 应用程序需要模型存数数据所以需要定义模型 —- 模型定义后需要激活才能使用所以需要激活模型—–由于修改了(创建)模型所以需要数据库的迁移
  4. 创建管理网站管理模型(非必须),只是为了更好管理模型
  5. 项目运行后,存储了一些数据,需要测试和排除故障时可以使用 Django shell(非必须),只是为了更好排除故障和测试
  6. 默认的欢迎主页肯定不是我们想要的,所以需要自己创建网页—-自己创建的网页,页面需要自己写,所以需要编写视图—-写完后需要告诉Django,让她返回我们自己写的视图,所以需要url映射—–映射后显示什么呢?我们写的视图是没有数据,所以还需要创建model,告诉视图你需要显示什么。(其他的页面创建也是这么一套结构下来)
  7. 有时候重复的代码写的多了就会想到抽取出来,这里也不例外,你可以抽取出父类的视图,让所有的子视图去继承她即可拥有父类的所有功能。
  8. 为了控制只有自己登录才能修改文章以及自己发布的文章自己能够记录下来,所有你可以创建一个用户的应用程序,从步骤 3 开始,Django 有用户系统,我们可以使用她自带的会方便很多。
  9. 部署到云服务器上,让别人也看看你写的内容有多酷!
小额支持我写出更好的文章~