使用Django+MySQL+Apache+Linux创建简单的博客
本教程基于慕课网<Django入门与实践>编写,基于CentOS 7
基础知识
什么是django?
Django是一个基于Python的高级Web开发框架, 特点:高效,快速,高度集成(不用自己弄底层),免费,开源
上网的流程
输入URL→向目标url发送http请求→服务器把页面响应给浏览器(通过后台编写的代码处理请求)→浏览器解析获取到的页面源代码文档(所以看到的不是html文档)→看到网页
目录结构
- 项目项目目录结构.
├── manage.py与项目进行交互的命令行工具集的入口(项目管理器)
└── myblog项目的一个容器,包含项目最基本的一些配置(不建议修改名称,会影响配置文件)
├── __init__.py声明模块的文件(默认为空,使myblog为一个模块,可以直接在代码中引用)
├── settings.py配置文件
├── urls.py配置页面url
└── wsgi.py(Python Web Server Gateway Interface 服务器网关接口,python应用与Web服务器之间的接口,)
manage.py
如root@localhost ~]#python manage.py runserver(直接输入python manage.py可以列出命令选项)
settings.py
项目的总配置文件,包含了数据库、web应用、时间等各种配置文件
import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #项目的跟目录 # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'qkotgzdcj-n!q#1@pwv7cyya!5$cuvqp3d=vrljrbuo48qvr5b' #启动项目所必须的安全码 # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True #调试,打开后异常会反馈给用户页面 ALLOWED_HOSTS = ['192.168.230.129'] #只允许外界通过【】内的地址访问 # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'zzb', ] #组成项目的应用,自己创建的应用需加进去 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] #中间件,自带的工具集 ROOT_URLCONF = 'blog.urls' #url的根文件,指向urls.py TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] #模板(html文件)配置 WSGI_APPLICATION = 'blog.wsgi.application' #把myblog当做一个模块 # Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases DATABASES = { 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 'ENGINE': 'django.db.backends.mysql', 'NAME':'blog', 'USER':'root', 'PASSWORD':'', 'HOST':'', 'PORT':'', 'OPTIONS':{ 'autocommit':True, }, } } #数据库配置,使用其他数据库需改动 # Password validation # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] #密码认证 # Internationalization # https://docs.djangoproject.com/en/1.11/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.11/howto/static-files/ STATIC_URL = '/static/' #静态文件的地址 STATIC_ROOT = '/var/www/html/blog/zzb/static/'
- 应用的目录结构
.├── admin.py (该应用的后台管理系统配置(django自带一个后台管理系统,每个应用都有各自的配置文件)
├── apps.py 该应用的一些配置,1.9版本后才有。
├── __init__.py
├── migrations 数据迁移模块
│ └── __init__.py(有这个文件说明它是一个模块)
├── models.py 数据模块(在其中创建数据表)使用ORM框架,类似于MVC结构中的Models(模型)
├── tests.py 自动测试模块,在这里编写测试脚本(语句)
└── views.py 执行响应的逻辑代码所在的模块,决定了接受web的请求后如何响应(项目中大部分在这里编写)
正式开始创建博客系统
搭建环境(建议源码安装,这里为了简便介绍yum | pip安装)
Python
- linux自带Python,无需安装,
- 低于2.7的版本与最新的Django不兼容
Django(自带一个小型的服务器)
安装(二选一)
- a) pip安装(需要本地有python-pip)
[root@localhost ~]#pip install Django==1.10.2
- b) 下载源码(执行效率更高),进入源码目录执行[root@localhost ~]#python setup.py install
判断安装是否完成
[root@localhost ~]# python -m django –-version
MySQL
yum install mariadb mariadb-server
mysql的使用请参考其他教程,这里不作介绍
将Django部署到Apache服务器上
安装mod_wsgi(yum install mod_wsgi)
修改apache配置文件(点击跳转后续详解)
配置项目中wsgi (点击跳转后续详解)
创建第一个项目
用django-admin创建项目
在/var/www/html目录下:
[root@localhost ~]#django-admin startproject blog(新命令django-admin) 会在/var/www/html/下生成一个新的文件夹blog
用manage.py创建应用
[root@localhost ~]#python manage.py startapp zzb
添加应用名到settings.py中的INSTALLED_APP里,
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'zzb', ]
修改settings.py,输入linux本机ip
ALLOWED_HOSTS = ['192.168.230.129']
创建第一个页面(响应)
在最后添加:
WSGIScriptAlias / /var/www/html/blog/blog/wsgi.py
WSGIPythonPath /var/www/html/blog
LoadModule wsgi_module modules/mod_wsgi.so
ErrorLog "logs/error_log" <Directory /var/www/html/blog/blog> <Files wsgi.py> Require all granted </Files> </Directory>
systemctl restart httpd
import os from django.core.wsgi import get_wsgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "blog.settings") application = get_wsgi_application()
- 编辑zzb/views
# Create your views here. from django.http import HttpResponse def index(request): return HttpResponse('hello,world')
每个函数必须返回一个响应,函数必须存在一个参数,一般约定为request,对应一个URL
- 配置urls.py(每个url都以url函数的形式写在urlpatterns列表中。三个参数(URL(正则),对应响应方法,名称zzb为应用名)
from django.conf.urls import url from django.contrib import admin import zzb.views as bv urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/',bv.index), ]
- 打开页面(192.168.230.129/index)
hellow,world
URL配置增强
- 修改blog下的url(注意url后面的/问题),引入include
from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^blog/',include('zzb.urls') ), ]
- 在app(zzb)下新建urls.py
from django.conf.urls import url from . import views urlpatterns = [ url(r'^index/$',views.index), ]
- 启动Apache,关闭防火墙
systemctl start httpd
systemctl stop firewalld
- 浏览器输入地址: http://192.168.230.129/blog/index/
hello,world
创建第一个Templates(模板)
- 在APP根目录下创建名叫templates(小写)的目录,
- 在templates目录下创建以app名为名称的目录,将html文件放入其中(解决templates冲突)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" > <title>Title</title> </head> <body> <h1>Hello,Blog</h1> </body> </html>
- 在views.py中返回render()
from __future__ import unicode_literals from django.shortcuts import render # Create your views here. from django.http import HttpResponse def index(request): return render(request,'index.html')
Models(模型)
一个model对应一张数据表,以类的形式表现,包含类一些基本字段以及数据的一些行为. ORM(object relation mapping)对象关系映射,不需要编写SQL语句
- 在settings.py中修改,使用MySQL代替django自带数据库.
DATABASES = { 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 'ENGINE': 'django.db.backends.mysql', 'NAME':'blog', 'USER':'root', 'PASSWORD':'', 'HOST':'', 'PORT':'', 'OPTIONS':{ 'autocommit':True, }, } }
- 在数据库中创建名为blog的数据库
在MySQL中执行:
CREATE DATABASE blog;
- pip安装pymysql插件
- 修改blog/__init__.py,添加
import pymysql pymysql.install_as_MySQLdb()
- 应用根目录下创建models.py,并引入models模块,创建类,继承models.Model,类即是一张数据表,在类中创建字段
from __future__ import unicode_literals from django.db import models # Create your models here. class Article(models.Model): title = models.CharField(max_length=32, default='Title') content = models.TextField(null=True) def _unicode_ (self): return self.title
- 生成数据表
[root@localhost ~]#python manage.py makemigrations
[root@localhost ~]#python manage.py migrate(会在app/migrations/目录下生成移植文件)
可以通过执行[root@localhost ~]#python manage.py sqlmigrate 应用名 文件id(查看SQL语句)
- 往数据库中写入数据
INSERT INTO zzb_article VALUE('1','2','3');
[root@192 ~]# mysql -uroot -p Enter password: MariaDB [(none)]> use blog; Database changed MariaDB [blog]> select * from zzb_article -> ; +----+-------+---------+ | id | title | content | +----+-------+---------+ | 1 | 2 | 3 | +----+-------+---------+ 1 row in set (0.00 sec)
- 取出数据
views.py中
1 # -*- coding: utf-8 -*- 2 from __future__ import unicode_literals 3 4 from django.shortcuts import render 5 6 # Create your views here. 7 from django.http import HttpResponse 8 from . import models 9 10 def index(request): 11 article = models.Article.objects.get(pk=1) 12 return render(request,'zzb/index.html',{'article':article})
- 页面呈现数据
<!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>
- 禁用SELinux
vi /etc/sysconfig/selinux 把里边的一行改为: SELINUX=disabled (不执行这一步则会出现2003报错), 重启生效
# This file controls the state of SELinux on the system. # SELINUX= can take one of these three values: # enforcing - SELinux security policy is enforced. # permissive - SELinux prints warnings instead of enforcing. # disabled - No SELinux policy is loaded. #SELINUX=enforcing SELINUX=disabled # SELINUXTYPE= can take one of three two values: # targeted - Targeted processes are protected, # minimum - Modification of targeted policy. Only selected processes are protected. # mls - Multi Level Security protection. SELINUXTYPE=targeted
- 打开浏览器,输入192.168.230.135/blog/index
Admin(自动化数据管理界面)
可直接在admin中管理数据库
- [root@localhost ~]#python manage.py createsuperuser
- 进入192.168.230.129/admin登录
- 更改语言,修改settings.py中LANGUAGE_CODE= ‘zh_Hans’(我的虚拟机改了就报错,然后就没去改)
- 配置应用
在应用下的admin.py中引入自身的models模块(或者里面的模型类)
在应用目录下的admin.py中做如下修改
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.contrib import admin from models import Article # Register your models here. admin.site.register(Article)
- 修改数据默认显示的名称(改了之后不知道为什么时而有效时而无效)
编辑应用下models.py,在Article类下添加一个方法,根据Python版本(3/2.7)选择_str_(self)或_unicode_(self)
- 关于admin页面没有css样式的解决办法
1. 去djando的解压包里的/doc/howto/static-files中查看帮助文档,找到解决办法
2. 在应用目录下创建static目录,在settings.py中添加STATIC_ROOT=’你的ststic的文件夹地址’
3. 在urls.py中添加修改
urlpatterns = [ # ... the rest of your URLconf goes here ... ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
4. 执行python manage.py collectstatic
博客开发
博客主页面开发
index.html
<!DOCTYPE HTML> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1> <a href="{% url 'zzb:edit_page' 0 %}">新文章</a> </h1> {% for article in articles %} <a href="{% url 'zzb:article_page' article.id %}">{{ article.title }}</a> <br/> {% endfor %} </body> </html>
博客文章页面开发
article_page.html
<!DOCTYPE HTML> <html lang="en"> <head> <meta charset="UTF-8"> <title>Article Page</title> </head> <body> <h1>{{ article.title }} </h1> <h3>{{ article.content }}</h3> <br/><br/> <a href="{% url 'zzb:edit_page' article.id %}">修改文章</a> </body> </html>
博客编辑页面开发
edit_page.html
<DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Edit Page</title> </head> <body> <form action="{% url 'zzb:edit_action' %}" method="post"> {% csrf_token %}
<!--上面一行用于跨站请求伪造保护措施--> {% if article %}
<!--如果有该文章--> <input type="hidden" name="article_id" value="{{ article.id }}">
<!--传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>
views.py配置
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.shortcuts import render from django.http import HttpResponse from . import models def index(request): articles = models.Article.objects.all() return render(request, 'zzb/index.html', {'articles':articles}) def article_page(request, article_id): article = models.Article.objects.get(pk=article_id) return render(request,'zzb/article_page.html',{'article':article}) def edit_page(request,article_id): if str(article_id) == '0': return render(request,'zzb/edit_page.html') article = models.Article.objects.get(pk=article_id) return render(request,'zzb/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 str(article_id) == '0':
#如果article_id为0 models.Article.objects.create(title=title,content=content) articles = models.Article.objects.all() return render(request,'zzb/index.html',{'articles':articles})
#如果不为0 article = models.Article.objects.get(pk=article_id) article.title = title article.content = content article.save() return render(request,'zzb/article_page.html',{'article':article})
url配置
from django.conf.urls import url from . import views urlpatterns = [ url(r'^index/$', views.index), url(r'^article/(?P<article_id>[0-9]+)/$', views.article_page, name='article_page'), url(r'^edit/(?P<article_id>[0-9]+)/$',views.edit_page, name='edit_page'), url(r'^edit/action/$',views.edit_action, name='edit_action'), ]
Templates过滤器
过滤器属于django模板语言, 修改模板中的变量,从而显示不同内容
{{ value | filter }}
举例:{{ list_nums | length}} 表示list的长度
{{ value | filter | filter | filter }} 可叠加
使用过滤器简化edit_page.html
<DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Edit Page</title> </head> <body> <form action="{% url 'zzb:edit_action' %}" method="post"> {% csrf_token %} <!--解决跨站请求伪造问题,POST表单需要添加这句--!> <input type="hidden" name="article_id" value="{{ article.id | default:'0'}}"> <!--default过滤器,默认值--!> <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交互式命令行程序,自动引入项目环境,可以使用它和项目进行交互
启动django shell
pyhton manage.py shell
交互举例:
from blog.models import Article
Article.objects.all()
作用:1)调试工作 2)测试未知的方法
Admin增强
配置admin.py,使其显示更多内容
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.contrib import admin from models import Article class ArticleAdmin(admin.ModelAdmin): list_display = ('title','content','pub_time')
#根据时间进行筛选的过滤器
list_filter = ('pub_time',)
# Register your models here. admin.site.register(Article,ArticleAdmin)
配置models.py,增加时间参数
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models # Create your models here. class Article(models.Model): title = models.CharField(max_length=32, default='Title') content = models.TextField(null=True) pub_time = models.DateTimeField(null=True) def _unicode_ (self): return self.title
执行数据迁移
进入admin:
写在最后:
- 有的情况修改urls.py后,需要重启apache才能看到效果,不知道为什么,请注意.
- 有的情况在templates下创建以应用为名的目录(解决冲突)后,Django不能读取放在其中的html文件,(很疑惑,不知道为什么)
如:
Django tried loading these templates, in this order: Using engine django: django.template.loaders.app_directories.Loader: /usr/lib64/python2.7/site-packages/django/contrib/admin/templates/index.html (Source does not exist) django.template.loaders.app_directories.Loader: /usr/lib64/python2.7/site-packages/django/contrib/auth/templates/index.html (Source does not exist) django.template.loaders.app_directories.Loader: /var/www/html/blog/zzb/templates/index.html (Source does not exist)
html文件放在zzb/templates/zzb下,然而Django没有检索这一目录,只能被迫把index.html放在templates目录下
- 厌倦了手动启动httpd,mariadb?
将他们添加到开机启动项:
只需使用chkconfig 服务名 on即可,若想关闭,将on改为off
- 如果出现如下错误,则是没有关闭SELinux,禁用后重启可解决.
- Python有严格的缩进要求,一个tab设置为4个空格,如上述文档有缩进错误,请自行更正
设置tab为4个空格:
vim ~/.vimrc
:
set
ts=4
:
set
expandtab
2017-07-29/22:26:38
如有错误,请评论指出