
环境安装和配置
pip install virtualenv -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install virtualenvwrapper-win
mkvirtualenv web #创建虚拟环境
workon web #切换到虚拟机环境
pip install django==2.2.7
#settings.py
ALLOWED_HOSTS = ['*']
LANGUAGE_CODE = 'zh-hans'
#TIME_ZONE = 'UTC'
USE_TZ = False
应用环境配置
创建应用
>cd <项目目录>
>python manage.py startapp blog
migrations
迁移文件集合
admin.py:项目的后台
apps.py:应用设置
models.py:模型(数据库)
views.py:视图(页面请求和响应)
注册应用
修改settings.py
INSTALLED_APPS = [
...
'blog.apps.BlogConfig'
]
数据库配置
启动mysql服务
[shuyun@master ~]$ sudo service mysqld start
Starting mysqld: [ OK ]用户: root
密码:123456
端口:3306
数据库连接参数:
确认虚拟机IP
[shuyun@master ~]$ ifconfig
eth5 Link encap:Ethernet HWaddr 00:50:56:3A:1F:12
inet addr:192.168.89.200 Bcast:192.168.89.255 Mask:255.255.255.0
settings.py完成mysql配置
开发环境
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}生产环境
DATABASES = {
'default':{
'ENGINE':'django.db.backends.mysql',
'NAME':'blog',
'USER':'root',
'PASSWORD':'123456',
'HOST':'192.168.89.200',
'PORT':3306,
}
}
安装pymysql
pip install PyMySQL
修改blogproj/init.py
import pymysql
pymysql.install_as_MySQLdb()
创建数据库和授权
[root@master ~]# mysql -uroot -p123456
mysql> create database blog;
mysql> grant all on blog.* to root@'%' identified by '123456';
创建管理员账号
用户:admin,密码:admin
python manage.py createsuperuser
数据模型
在models.py中完成如下配置
博客模型
from django.db import models
from django.contrib.auth.models import User
#文章类别
class Category(models.Model):
#默认自动生成id字段作为主键
name = models.CharField(verbose_name='名称', max_length=100)
#标签
class Tag(models.Model):
#默认自动生成id字段作为主键
name = models.CharField(verbose_name='名称', max_length=100)
class Post(models.Model):
title = models.CharField(verbose_name='标题', max_length=100)
body = models.TextField(verbose_name='正文') #TextField存储大段文本
create_time = models.DateTimeField(verbose_name='创建时间')
modified_time = models.DateTimeField(verbose_name='修改时间')
excerpt = models.CharField(verbose_name='摘要',max_length=255)
category = models.ForeignKey(Category, on_delete=models.CASCADE,verbose_name='类别') #一对多
tags = models.ManyToManyField(Tag, blank=True,verbose_name='标签') #多对多
author = models.ForeignKey(User,on_delete=models.CASCADE,verbose_name='用户')
数据库迁移
python manage.py makemigrations #创建迁移文件
python manage.py migrate #迁移到数据库
ORM操作
存数据
>python manage.py shell
In [1]: from blog.models import Category,Tag,Post
#写入类别
In [2]: cate = Category(name='test cate1')
In [3]: cate.save()
#写入标签
In [4]: tag = Tag(name='test tag1')
In [5]: tag.save()
#写入博客
In [2]: from django.contrib.auth.models import User
In [8]: from django.utils import timezone
In [4]: user = User.objects.get(username='admin')
In [7]: post = Post(title='title_test1',body='body_test1',create_time=timezone.now(),modified_time=timezone.now(),category=cate,author=user)
post.save()
读数据
#读取category
In [18]: cateall = Category.objects.all()
In [19]: cateall
Out[19]: <QuerySet [<Category: Category object (1)>, <Category: Category object (2)>]>
In [20]: cateall[0]
Out[20]: <Category: Category object (1)>
In [21]: cateall[0].name
Out[21]: 'test cate1'
#TODO练习:读取post的body数据
In [22]: post = Post.objects.all()
In [23]: post[0].body
Out[23]: 'body_test1'
删数据
#删类别
In [24]: cate1 = Category.objects.get(name='test cate1')
In [26]: cate1.delete()
Out[26]: (1, {'blog.Category': 1})
#TODO练习:删除post数据
In [27]: post = Post.objects.get(id=1)
In [28]: post.delete()
Out[28]: (1, {'blog.Post_tags': 0, 'blog.Post': 1})
视图
视图函数
修改了blog/views.py
from django.http import HttpResponse
def index(request):
return HttpResponse("欢迎学习Django!")
URL绑定
配置项目URL:blogproj/urls.py
....
from django.conf.urls import url,include
urlpatterns = [
...
url(r'',include('blog.urls'))
]在blog项目目录下创建urls.py文件
添加代码
from django.conf.urls import url,include
from . import views
urlpatterns = [
url(r'', views.index, name='index')
]启动开发服务
python manage.py runserver #默认8000端口
#Starting development server at http://127.0.0.1:8000/
python manage.py runserver 127.0.0.1:8001 #指定端口启动浏览器访问

模板系统
模板指静态页面(html)
静态文件:css、js
创建templates/blog目录,新建index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h1>{{ welcome }}</h1>
</body>
</html>
{{ title }},{{ welcome }}:模板变量
修改views.py
def index(request):
context = {'title':"Dylan的Blog", 'welcome':'欢迎来到我的博客'}
return render(request, 'blog/index.html', context=context)
刷新页面

博客首页
静态文件
拷贝模板
项目目录下创建static/blog目录
拷贝css和js到上述目录
拷贝index.html到templates/blog目录
修改settings
STATIC_ROOT = os.path.join(BASE_DIR,'static') #新增
修改index.html
{% load static %}
...
<!-- css -->
<link rel="stylesheet" href="{% static 'blog/css/bootstrap.min.css' %}">
<link rel="stylesheet" href="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
<link rel="stylesheet" href="{% static 'blog/css/pace.css' %}">
<link rel="stylesheet" href="{% static 'blog/css/custom.css' %}">
<!-- js -->
<script src="{% static 'blog/js/jquery-2.1.3.min.js' %}"></script>
<script src="{% static 'blog/js/bootstrap.min.js' %}"></script>
<script src="{% static 'blog/js/pace.min.js' %}"></script>
<script src="{% static 'blog/js/modernizr.custom.js' %}"></script>
</head>
...
<script src="{% static 'blog/js/script.js' %}"></script>
</body>
...
模板修改
视图
修改views.py
...
from .models import Post
def index(request):
post_list = Post.objects.all().order_by("-create_time") #按照创建时间降序排列
context = {'post_list':post_list}
return render(request, 'blog/index.html', context=context)
模板
文章列表
删除index.html的多余article,只保留1个

修改模板
遍历博客
{% for post in post_list %}
<article class="post post-{{ post.id }}">
...
</article>
{% empty %}
<div class="no-post">暂时没有发布的文章!</div>
{% endfor %}
标题
<h1 class="entry-title">
<a href="single.html">{{ post.title }}</a>
</h1>
详情
<div class="entry-meta">
<span class="post-category"><a href="#">{{ post.category.name }}</a></span>
<span class="post-date"><a href="#"><time class="entry-date"
datetime="{{ post.create_time }}">{{ post.create_time }}</time></a></span>
<span class="post-author"><a href="#">{{ post.author.username }}</a></span>
...
</div>
摘要
<div class="entry-content clearfix">
<p>{{ post.excerpt }}</p>
...
后台
注册模型
修改blog/admin.py
from .models import Category,Tag,Post
admin.site.register(Category)
admin.site.register(Tag)
admin.site.register(Post)
汉化
应用汉化, apps.py
class BlogConfig(AppConfig):
name = 'blog'
verbose_name = '博客'
模型汉化, models.py
class Category(models.Model):
...
class Meta:
verbose_name='类别'
verbose_name_plural = verbose_name #复数形式
class Tag(models.Model):
...
class Meta:
verbose_name='标签'
verbose_name_plural = verbose_name #复数形式
class Post(models.Model):
...
class Meta:
verbose_name='文章'
verbose_name_plural = verbose_name #复数形式
返回结果(对象->字符串)
class Category(models.Model):
...
def __str__(self):
return self.name
class Tag(models.Model):
...
def __str__(self):
return self.name
class Post(models.Model):
...
def __str__(self):
return self.title
定制后台
只显示需要的字段
admin.site.register(Category)
admin.site.register(Tag)
class PostAdmin(admin.ModelAdmin):
list_display = ['title','create_time','modified_time','category','author']
admin.site.register(Post,PostAdmin)
控制表单展示的字段和填充当前用户作为作者
admin.py
...
class PostAdmin(admin.ModelAdmin):
list_display = ['title','create_time','modified_time','category','author']
fields = ['title','body','excerpt','category','tags']
def save_model(self, request, obj, form, change):
obj.author = request.user #当前用户赋值
super().save_model(request, obj, form, change)
...
自动填充创建时间和修改时间
models.py
from django.utils import timezone
class Post(models.Model):
...
create_time = models.DateTimeField(verbose_name='创建时间',default=timezone.now)
...
def save(self, *args, **kwargs):
self.modified_time = timezone.now() #修改时间的自动调整
super().save(*args,**kwargs)
详情页
URL映射
url绑定
blog/urls.py
urlpatterns = [
path(r'', views.index, name='index'),
path('posts/<int:pk>', views.detail, name='detail')
]视图
views.py
from django.shortcuts import render,get_object_or_404
...
def detail(request,pk):
post = get_object_or_404(Post, pk=pk)
context = {'post':post}
return render(request,'blog/detail.html',context)模板
把single.html拷贝到templates/blog目录,更名为detail.html
blog/urls.py增加app_name
app_name = 'blog'
...index.html
<header class="entry-header">
<h1 class="entry-title">
<a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
</h1>models.py
from django.urls import reverse
...
class Post(models.Model):
...
def get_absolute_url(self):
return reverse('blog:detail', kwargs={'pk':self.pk})
模板继承
模板页
创建templates/base.html,把index.html的内容拷贝过来,修改如下:
<div class="content-body">
...
<main class="col-md-8">
{% block main %}
{% endblock main %}
</main>
<aside class="col-md-4">
{% block aside %}
{% endblock aside %}
</aside>
...
</div>
主页继承模板
修改index.html
{% extends 'base.html' %}
{% block main %}
{% for post in post_list %}
<article class="post post-{{ post.id }}">
...
</article>
{% empty %}
<div class="no-post">暂时没有发布的文章!</div>
{% endfor %}
<div class="pagination">
...
</div>
{% endblock main %}
详情页继承模板
{% extends 'base.html' %}
{% block main %}
<article class="post post-{{ post.pk }}">
<header class="entry-header">
<h1 class="entry-title">{{ post.title }}</h1>
<div class="entry-meta">
<span class="post-category"><a href="#">{{ post.category.name }}</a></span>
<span class="post-date"><a href="#"><time class="entry-date"
datetime="{{ post.create_time }}">{{ post.create_time }}</time></a></span>
<span class="post-author"><a href="#">{{ post.author.username }}</a></span>
<span class="comments-link"><a href="#">4 评论</a></span>
<span class="views-count"><a href="#">588 阅读</a></span>
</div>
</header>
<div class="entry-content clearfix">
{{ post.body }}
</div>
</article>
<section class="comment-area" id="comment-area">
...
{% endblock main %}
{% block aside %}
<div class="widget widget-content">
...
</div>
{% endblock aside %}
静态文件处理
把/static 移动到/blog目录下,并重启runserver
支持Markdown
安装
>pip install markdown修改detail视图,支持markdown
...
def detail(request,pk):
post = get_object_or_404(Post, pk=pk)
#把markdown转换成html标签
post.body = markdown.markdown(post.body, extensions=[
'markdown.extensions.extra',
'markdown.extensions.codehilite',
'markdown.extensions.toc',
])
context = {'post':post}
return render(request,'blog/detail.html',context)
...
detail.html增加safe标签,解除html转义
<div class="entry-content clearfix">
{{ post.body|safe }}
</div>
自动生成目录
修改views.py
def detail(request,pk):
post = get_object_or_404(Post, pk=pk)
md = markdown.Markdown(extensions=[
'markdown.extensions.extra',
'markdown.extensions.codehilite',
'markdown.extensions.toc',
])
# 把markdown转换成html标签
post.body = md.convert(post.body)
post.toc = md.toc #目录
context = {'post':post}
return render(request,'blog/detail.html',context)
修改detail.html
{% block aside %}
<div class="widget widget-content">
<h3 class="widget-title">文章目录</h3>
{{ post.toc|safe }}
</div>
...
自动摘要生成
重写save,修改摘要
models.py
class Post(models.Model):
...
def save(self, *args, **kwargs):
self.modified_time = timezone.now() #修改时间的自动调整
#生成摘要
md = markdown.Markdown(extensions=[
'markdown.extensions.extra',
'markdown.extensions.codehilite',
])
self.excerpt = strip_tags(md.convert(self.body))[:50]
super().save(*args,**kwargs)
前端使用摘要标签
index.html
</header>
<div class="entry-content clearfix">
<p>{{ post.excerpt }}</p>
方法2:直接用模板过滤器
index.html
<div class="entry-content clearfix">
<p>{{ post.body|truncatechars:60 }}</p>
自定义模板标签
创建blog/templatetags/blog_extras.py,templatetags是package
创建templates/blog/inclusions目录,用来存放模板标签html
最新文章
定义模板标签
blog_extras.py添加
from blog.models import Post,Category,Tag
from django import template
register = template.Library()
@register.inclusion_tag('blog/inclusions/_recent_posts.html',takes_context=True)
def show_recent_posts(context,num=3):
post_list = Post.objects.all().order_by('-create_time')[:num]
return {'recent_post_list':post_list}
添加模板
创建templates/blog/inclusions/_recent_posts.html
<div class="widget widget-recent-posts">
<h3 class="widget-title">最新文章</h3>
<ul>
{% for post in recent_post_list %}
<li>
<a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
</li>
{% empty %}
暂无文章!
{% endfor %}
</ul>
</div>
使用模板标签
base.html
{% load blog_extras %}
...
<aside class="col-md-4">
{% block aside %}
{% endblock aside %}
{% show_recent_posts %}
</aside>
分类
注册分类模板标签:show_categories
blog_extras.py
...
@register.inclusion_tag('blog/inclusions/_categories.html', takes_context=True)
def show_categories(context):
return {'category_list':Category.objects.all()}创建模板:_categories.html
<div class="widget widget-category">
<h3 class="widget-title">分类</h3>
<ul>
{% for cate in category_list %}
<li>
<a href="#">{{ cate.name }} <span class="post-count">(13)</span></a>
</li>
{% empty %}
暂无分类!
{% endfor %}
</ul>
</div>
使用模板标签
base.html
...
<aside class="col-md-4">
...
{% show_categories %}
</aside>
练习1:模板标签
归档
标签云
其他页面
分类
视图函数
views.py
from .models import Post,Category
...
def category(request, pk):
cate = get_object_or_404(Category, pk=pk) #类别对象
post_list = Post.objects.filter(category=cate).order_by('-create_time')
return render(request, 'blog/index.html', context={'post_list':post_list})url映射
blog/urls.py
urlpatterns = [
...
path('categories/<int:pk>', views.category, name='category'),
]模板页面跳转
修改blog/inclusions/_categories.html
...
<li>
<a href="{% url 'blog:category' cate.pk %}">{{ cate.name }} <span class="post-count">(13)</span></a>
...
练习2
标签页
归档页
部署
环境搭建
python3安装、虚拟环境,依赖包
激活虚拟环境
source home/shuyun/web/bin/activate创建项目目录并授权给shuyun
mkdir -p home/shuyun/program
chown -R shuyun.shuyun home/shuyun/program项目打包,上传到服务器(put、svn、git)的/home/shuyun/program
解压项目文件
cd home/shuyun/program
unzip blogproj.zip测试
cd home/shuyun/program/blogproj
python manage.py runserver 0.0.0.0:8000
浏览器访问 http://服务器IP:8000
使用gunicorn
确保服务器可以访问公网
安装
pip3 install gunicorn启动服务到后台
nohup gunicorn blogproj.wsgi -w 2 -k gthread -b 0.0.0.0:8000 &浏览器访问: http://服务器IP:8000
Nginx
安装
# yum install nginx -y
配置修改
/etc/nginx/nginx.conf
user shuyun;
...创建/etc/nginx/conf.d/blogproj.conf
server {
charset utf-8;
listen 8080;
server_name 0.0.0.0;
location static {
alias home/shuyun/program/blogproj/static;
}
location {
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8000;
}
}启动服务
# service nginx start
收集静态文件
$ python manage.py collectstatic
浏览器访问:http://192.168.89.200:8080/
图文 / 来源网络
版权归原作者所有,侵联删



碧茂课堂精彩课程推荐:
1.Cloudera数据分析课;
2.Spark和Hadoop开发员培训;
3.大数据机器学习之推荐系统;
4.Python数据分析与机器学习实战;

详情请关注我们公众号:碧茂大数据-课程产品-碧茂课堂
现在注册互动得海量学币,大量精品课程免费送!

关注最新行业动态,
加群进行技术交流!




