Django-blog-demo笔记。


搭建

环境

  python 3.7
  Django 2.1.5
  pycharm

安装

  cmd里敲:

1
pip install Django==2.1.5

创建项目和应用

创建项目

  在预想安装博客目录下计入cmd,敲:

1
django-admin startproject myblog

  对应目录下生成一个myblog文件夹。

  manage.py:与项目进行交互的命令行工具集的入口

1
python manage.py

  查看所有命令。

  启动命令:

1
python manage.py runserver

  浏览器127.0.0.1:8000查看效果。

  改端口号:

1
python manage.py runserver 8888

myblog目录

  myblog
  |–__init__.py
  |–settings.py
  |–urls.py
  |–wsgi.py
  manage.py

  wsgi.py
  WSGI(Python Web Server Gateway Interface) Python服务器网关接口
  Python应用与Web服务器之间的接口

  urls.py
  URL配置文件

  settings.py
  项目总配置文件,包含数据库、Web应用、时间等各种配置

  __init__.py
  内容默认为空

创建应用

  打开命令行,进入manage.py同级目录

1
python manage.py startapp blog

  会多一个blog文件夹。
  添加应用名到settings.py中的INSTALLED_APPS里

1
2
3
4
5
6
7
8
9
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog'
]

blog目录

  blog
  |–migrations
  |—-__init__.py
  |–__init__.py
  |–admin.py
  |–apps.py
  |–models.py
  |–tests.py
  |–views.py

  migrations 数据移植(迁移)模块,内容自动生成

  admin.py 该应用的后台管理系统配置
  apps.py 应用配置(Django-1.9以后自动生成)
  models.py 数据模块,使用ORM框架,类似于MVC结构中的Models(模型)
  test.py 自动化测试模块,在此编写测试脚本(语句)
  views.py 执行响应的代码所在模块,代码逻辑处理地(项目大部分代码在此)

Hello World

  打开view.py,输入

1
2
3
4
5
from django.shortcuts import render
from django.http import HttpResponse

def index(request):
return HttpResponse('Hello World!')

  即编辑blog.views
  每个相应对应一个函数,函数必须返回一个响应
  函数必须存在一个参数,一般约定为request
  每个相应(函数)对应一个URL

在urls.py中,输入

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

import blog.views as bv

urlpatterns = [
path('admin/', admin.site.urls),
path('index/', bv.index),
]

  即编辑urls.py
  url函数放在urlpatterns列表中
  url函数三个参数:URL(正则),对应方法,名称

  运行,输入地址http://localhost:8000/index/ 即可。

第二种URL配置

  如果页面很多,都写在根urls.py中就很乱。于是,在根urls.py中引入include,在APP目录下创建urls.py文件,格式与根urls.py相同。

  更改后:

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

import blog.views as bv

urlpatterns = [
path('admin/', admin.site.urls),
path('index/', include('blog.urls')),
]

  新blog.urls.py

1
2
3
4
5
6
7
from django.urls import path

from . import views

urlpatterns = [
path('', views.index),
]

Templates

  HTML文件使用了Django模板语言(Django Template Language, DTL)

开发第一个Template

  • 在APP的根目录下创建名叫Templates的目录
  • 在该目录下创建HTML文件
  • 在views.py中返回render()

  html中敲入:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Hello blog!</h1>
</body>
</html>

  修改views.py为:

1
2
3
4
5
from django.shortcuts import render
from django.http import HttpResponse

def index(request):
return render(request,'index.html')

  运行查看效果。

DTL初步使用

  render()函数中支持一个dict类型参数
  该字典是后台传递到模板的参数,键为参数名
  在模板中使用来直接使用

  修改views.py

1
2
3
...
return render(request,'index.html',{'hello':'Hello blog!'})
...

  修改html

1
2
3
...
<h1>{{hello}}</h1>
...

  运行查看效果。

Models

  通常,一个Model对应数据库的一张数据表
  Django中Models以类的形式表现
  它包含了一些基本字段以及数据的一些行为

ORM

  对象关系映射(Object Relation Mapping)
  实现了对象和数据库之间的映射
  隐藏了数据访问的细节,不需要编写SQL语句

编写Models

  • 在应用根目录下创建models.py,并引入models模块
  • 创建类,继承models.Model,该类即是一张数据表
  • 在类中创建字段

字段创建

  字段即类里面的属性(变量)

1
attr = models.CharField(max_length = 64)

生成数据表

  命令行中进入manage.py同级目录
  执行命令

1
2
python manage.py makemigrations app名(可选)
python manage.py migrate

  不加app名默认给所有app进行数据迁移。

  cmd将显示:

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
E:\PythonCode\myblog>python manage.py makemigrations
Migrations for 'blog':
blog\migrations\0001_initial.py
- Create model Article

E:\PythonCode\myblog>python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, blog, 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 admin.0003_logentry_add_action_flag_choices... 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 blog.0001_initial... OK
Applying sessions.0001_initial... OK

生成数据表

  查看
  Django会自动在app/migrations/目录下生成移植文件
  执行命令查看SQL语句

1
python manage.py sqlmigrate 应用名 文件id

  cmd将显示:

1
2
3
4
5
6
7
E:\PythonCode\myblog>python manage.py sqlmigrate blog 0001
BEGIN;
--
-- Create model Article
--
CREATE TABLE "blog_article" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(32) NOT NULL, "content" text NULL);
COMMIT;

  默认sqlite3的数据库在项目根目录下db.sqlite3
  查看并编辑db.sqlite3,使用第三方软件,如SQLite Expert Personal

页面呈现数据

后台步骤

  views.py中import models

1
2
article = models.Article.objects.get(pk = 1)
render(request, page, {'article':article})

后端步骤

  模板可直接使用对象以及对象的“.”操作

  修改html

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{article.title}}</h1>
<h3>{{article.content}}</h3>
</body>
</html>

  运行,查看http://localhost:8000/index/

Admin

Django自带的一个功能强大的自动化数据管理界面
被授权的用户可直接在Admin中管理数据库
Django提供了许多针对Admin的定制功能

配置Admin

创建用户

创建超级用户

1
python manage.py createsuperuser

之后要求输入用户名
邮箱
密码

Admin入口访问地址:localhost:8000/admin/

如需修改成中文版,修改settings.py中LANGUAGE_CODE = ‘zh_Hans’
(英文:LANGUAGE_CODE = ‘en-us’)

配置应用

在应用下admin.py中引入自身的models模块(或里面的模型类)
编辑admin.py

1
2
from .models import Article
admin.site.register(models.Article)

修改数据

点击Article超链接进入Article列表页面,按页面指示修改。

修改数据默认显示名称

每条都显示的Article object,很不方便,显示文章标题比较好。

  • 在Article类下添加一个方法
  • 根据Python版本选择str(self) (python3以上)或unicode(self) (python2.7)
  • return self.title

博客开发

页面设计

  博客主页面
  博客文章内容页面
  博客撰写页面

主页面内容

  文章标题列表,超链接
  发表博客按钮(超链接)

列表编写思路

  • 取出数据库中所有文章对象
  • 将文章对象们打包成列表,传递到前端
  • 前端页面把文章以标题超链接的形式逐个列出

  模板For循环

1
2
3
{%for xx in xxs%}
# HTML语句
{%endfor%}

  修改views.py

1
2
3
4
5
6
7
from django.shortcuts import render
from django.http import HttpResponse

from . import models
def index(request):
articles = models.Article.objects.all()
return render(request,'index.html',{'articles': articles})

  修改html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>
<a href="">新文章</a>
</h1>
{% for article in articles %}
<a href="">{{article.title}}</a>
<br/>
{% endfor %}
</body>
</html>

页面内容

  标题
  文章内容
  修改文章按钮(超链接)

  在templates中新增article_page.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Article Page</title>
</head>
<body>
<h1>{{article.title}}</h1>
<br/>
<h3>{{article.content}}</h3>
<br/><br/>
<a href="">修改文章</a>
</body>
</html>

  修改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
from django.shortcuts import render
from django.http import HttpResponse

from . import models
def index(request):
articles = models.Article.objects.all()
return render(request,'index.html',{'articles': articles})

def article_page(request, article_id):
article=models.Article.objects.get(pk = article_id)
return render(request,'article_page.html',{'article':article})
``
### URL传递参数
  参数写在相应函数中request后,可以有默认值

  修改blog下的urls.py
```py
from django.urls import path

from . import views

urlpatterns = [
path('', views.index),
path('article/<article_id>', views.article_page),
]

  顺便把myblog\urls.py里的index改成blog(非必要,只是更符合博客url)

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

import blog.views as bv

urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls')),
]

  运行,输入http://localhost:8000/blog/article/1 查看。

超链接

  href后是目标地址,template中可用

1
{%url 'app_name:url_name' param%}

  其中app_name和url_name都在url中配置

再配URL

uel函数的名称参数

  法一:根urls,写在include()的第二个参数位置,namespace='blog'
  法二:应用下则写在url()的第三个参数位置,name='article'
  主要取决于是否使用include引用了另一个url配置文件

撰写页面

  标题编辑栏
  文章内容编辑区域
  提交按钮

  新建edit_page.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Edit Page</title>
</head>
<body>
<form action="" method="post">
<label>文章标题
<input type="text" name="title"/>
</label>
<br/>
<label>文章内容
<input type="text" name="content"/>
</label>
<br/>
<input type="submit" value="提交"/>
</form>
</body>
</html>

  views.py新增

1
2
def edit_page(request):
return render(request,'edit_page.html')

  blog\urls.py新增

1
path('edit', views.edit_page),

  运行,输入http://localhost:8000/blog/edit 查看。

编辑相应函数

  使用request.POST['参数名']获取表单数据
  models.Article.objects.create(title, content)创建对象

两个编辑页面

  思路:新文章为空,修改文章有内容
  修改文章页面有文章对象
  文章的ID

  修改数据
  article.title = title
  article.save()

  修改views.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def edit_page(request, article_id):
if str(article_id) == '0':
return render(request,'edit_page.html')
article = models.Article.objects.get(pk=article_id)
return render(request, 'edit_page.html', {'article': article})


def edit_action(request):
title = request.POST.get('title', 'TITLE')
content = request.POST.get('content', 'CONTENT')
article_id = request.POST.get('article_id', '0')

if article_id == '0':
models.Article.objects.create(title=title, content=content)
articles = models.Article.objects.all()
return render(request, 'index.html', {'articles': articles})

article = models.Article.objects.get(pk=article_id)
article.title = title
article.content = content
article.save()
return render(request,'article_page.html', {'article': article})

  修改blog\urls.py

1
2
3
4
5
6
urlpatterns = [
path('', views.index),
path('article/(?P<article_id>[0-9]+)$', views.article_page,name='article_page'),
path('edit/(?P<article_id>[0-9]+)$', views.edit_page,name='edit_page'),
path('edit/Action$', views.edit_action,name='edit_action'),
]

  修改article_page.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Article Page</title>
</head>
<body>
<h1>{{article.title}}</h1>
<br/>
<h3>{{article.content}}</h3>
<br/><br/>
<a href="{% url 'blog:edit_page' article.id %}">修改文章</a>
</body>
</html>

  修改主页index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>
<a href="{% url 'blog:edit_page' 0 %}">新文章</a>
</h1>
{% for article in articles %}
<a href="{% url 'blog:article_page' article.id %}">{{article.title}}</a>
<br/>
{% endfor %}
</body>
</html>

  修改edit_page.gtml

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Edit Page</title>
</head>
<body>
<form action="{% url 'blog:edit_action' %}" method="post">
{% csrf_token %}
{% if article %}
<input type="hidden" name="article_id" value="{{article.id}}"/>
<label>文章标题
<input type="text" name="title" value="{{article.title}}"/>
</label>
<br/>
<label>文章内容
<input type="text" name="content" value="{{article.content}}"/>
</label>
<br/>
{% else %}
<input type="hidden" name="article_id" value="0"/>
<label>文章标题
<input type="text" name="title"/>
</label>
<br/>
<label>文章内容
<input type="text" name="content"/>
</label>
<br/>
{% endif %}
<input type="submit" value="提交">
</form>
</body>
</html>

Templates过滤器

  写在模板中,属于Django模板语言
  可以修改模板中的变量,从而显示不同的内容
  使用

1
{{value | filter}}

e.g.

1
{{list_nums | length}}

  过滤器可叠加:

1
{{value | filter1 | filter2 | ...}}

  修改edit_page.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Edit Page</title>
</head>
<body>
<form action="{% url 'blog:edit_action' %}" method="post">
{% csrf_token %}
<input type="hidden" name="article_id" value="{{article.id | default:'0'}}"/>
<label>文章标题
<input type="text" name="title" value="{{article.title}}"/>
</label>
<br/>
<label>文章内容
<input type="text" name="content" value="{{article.content}}"/>
</label>
<br/>
<input type="submit" value="提交">
</form>
</body>
</html>

Django Shell

  Python交互式命令行程序,自动引入了项目环境,可使用它与项目进行交互
  使用

1
2
3
python manage.py shell
from blog.models import Article
Article.objects.all()

  可以使用它进行调试
  测试未知的方法

Admin增强

创建admin配置类

  class ArticleAdmin(admin.ModelAdmin)
  注册:admin.site.register(Article, ArticleAdmin)

显示其他字段

  list_display = (‘title’, ‘content’)
  list_display同时支持tuple和list

  修改admin.py

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

from .models import Article

class ArticleAdmin(admin.ModelAdmin):
list_display = ('title', 'content','pub_time')

admin.site.register(Article, ArticleAdmin)

  修改models.py

1
2
3
4
5
6
7
8
9
10
from django.db import models


class Article(models.Model):
title = models.CharField(max_length=32, default='Title')
content=models.TextField(null=True)
pub_time = models.DateTimeField(auto_now=True)

def __str__(self):
return self.title

  如果是

1
pub_time = models.DateTimeField(null=True)

  则可自己设定时间。

  修改完代码记得进行数据移植

1
2
python manage.py makemigrations
python manage.py migrate

过滤器

  list_filter = (‘pub_time’,)
  注意有个逗号

相关资料

Django API Reference

代码下载

django-blog-demo


hexo天坑:
遇到 两个大括号 以及 一个大括号一个% 一定放入代码行(如下),这样是不行的

1
2
{{}}
{%%}

排查这个bug花了我半个小时…