django写一个简单的博客,具备简单的展示,登录,注销,写博客的功能,发邮件.....的功能,然后通过apache部署在阿里云的云服务器上。简单来说这篇博客大致是这样,但是因为,断断续续的写,网站又要认证又要备案,过程对第一次部署网站的人来说确实还是比较麻烦的。
编程环境:
- python 2.7
- Django 1.11.4
- virtualenv
- Pillow 4.2.1
- django-mailgun 0.9.1
- django-simple-captcha 0.5.5
- apache
一、网站框架的基本搭建
首先,我们在本机上的虚拟机上编写django,操作以及调试,等做好后,直接就可以通过Git下载到云服务器上。新建一个文件夹www,建立一个虚拟机环境VENV,创建一个django项目,并且创建app。
mkdir www
virtualenv VENV
source VENV/bin/activate
cd www
django-admin startproject myweb
cd myweb
python manage.py startapp mysite
使用默认的SQLite存储数据库,新建db.sqlite3的文件。
python manage.py migrate
这里先把版本控制系统的Github的上传与下载说下,先要去Github上注册,而且在Github上新建一个repository,工程名需要和myweb一样。也就是和Django创建的工程一样。先安装git,设置自己的用户名和电子邮箱,当然虚拟环境安装的套件我们可以通过pip freeze建立套件列表。然后把所有使用到的套件更新一份记录在requirements.txt文本文件中,然后把这个文件作为项目的一份子,也commit到Github的文档库中,并使用git push同步到远程文档库中。
sudo apt-get install -y git
git config --global user.name '你的github的帐号名'
git config --global user.email '你的github的注册邮箱'
#将myweb下的所有资料上传一份到Github
cd myweb
git init
git remote add origin http://********/myweb.git#这个网址是git的工程的网址
git add .
git commit -m 'first commit'
git push origin master
#将虚拟环境安装的套件也上传到Github
pip freeze > requirements.txt
git add .
git commit -m 'add requirements.txt'
git push
#从Github中下载工程
#在服务器上也需要建立一个虚拟环境
git clone https://********/myweb.git
常规设置settings.py,models.py,urls.py,views.py等文件,并创建后台管理员帐号。先展示最后的一个目录树,其中的文件夹需要自己建立或者去下载的。
settings.py:
# -*- coding: utf-8 -*-
"""
Django settings for myweb project.
Generated by 'django-admin startproject' using Django 1.11.4.
For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""
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 = '#&3)e^6s#@y_a_u3fvcg@1ju$1zt#7bav%ym&s=^plcku%^7a6'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['*']#设置访问头为'*',即都可以访问
#Mailgun settings
#设置发送邮件的功能
EMAIL_BACKEND = 'django_mailgun.MailgunBackend'
MAILGUN_ACCESS_KEY = 'key-a0d0fa0de904bed6df040d6a71202fd1'
MAILGUN_SERVER_NAME = 'sandbox47c349b6fcbc4184920573b1f29f6006.mailgun.org'
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'mysite',#之前建立的app
'DjangoUeditor',#后面用到的文本编辑器
'captcha',#图片认证
]
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 = 'myweb.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates')],
'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',
],
},
},
]
WSGI_APPLICATION = 'myweb.wsgi.application'
# 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'),
}
}
# 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 = 'zh-hans'#修改语言
TIME_ZONE = 'Asia/Shanghai'#修改时区
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 = os.path.join(BASE_DIR,'staticfiles')
#static
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'static'),
os.path.join(BASE_DIR,'com_static'),
os.path.join(BASE_DIR,'media'),
]
#upload floder
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
STATICFILES_FINDERS = ("django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",)
转:
- MEDIA_ROOT:主要是为了存放上传的文件,比如在ImageField中,这个值加上upload_to的值就是真实存放上传图片的文件位置;Django里边文件内容实际上是不会存放到数据库里边的,大多数数据库存放数据效率低,需要保存在文件系统里。PS:FileUploads(用来存储文件)
- MEDIA_URL:URL的映射,前后要加上‘/’ 表示从根目录开始,比如“/site_media/”,加上这个属性之后,静态文件的链接前面会加上这个值。
- STATIC_ROOT:在这个文件里边的目录会当成静态文件处理。但是不能把自己辛苦写的Javascript或者图片等静态文件放进去。
- STATIC_URL:URL映射,指定静态目录的URL,默认的是"/static/"。一般是指在各个app下的static,用来存放静态资源。
- STATICFILES_DIRS:指定一个工程里边哪个目录存放了与这个工程相关的静态文件,是一个列表。。一般用来设置通用的静态资源,对应的目录不放在APP下,而是放在Project下,例如:
STATICFILES_DIRS=(os.path.join(BASE_DIR, "common_static"),)
具体在模板文件中访问的时候,都是统一用:/static/资源名的方式,就可以访问到资源,不论具体的目录是APP下的static,还是project下的common_static, 都可以用/static/资源名的方式访问到。如果列表中有一个是 “/home/shishang/test/static”,其中有一个文件内容是productlist.html, 我们只要访问http://localhost:8000/static/productlist.html就可以直接访问界面了
Django提供了一个方法自动地将所有的静态文件放在一起。只要在写App的时候创建一个static子目录专门保存静态文件就行了。在开发阶段,不必费心去做映射,不需要配置urls.py
。在布署到生产环境的时候,只需要配置Apache把/static/
映射到STATIC_ROOT
。然后运行
python manage.py collectstatic
自动地STATICFILES_DIRS
列出的目录以及各个App下的static子目录的所有文件复制到STATIC_ROOT。因为复制过程可能会覆盖掉原来的文件,所以,一定不能把我们辛苦做出来静态文件放这边!在开发阶段,Django把/static
映射到django.contrib.staticfiles
这个App。staticfiles
自动地从STATICFILES_DIRS
、STATIC_ROOT
以及各个App的static
子目录里面搜索静态文件。一旦布署到开发环境上,settings.py不需要重新编写,只要在Apache的配置文件里面写好映射,/static
将会被Apache处理。django.contrib.staticfiles
虽然仍然存在,但因为不会接收到以/static/
开始的路径,所以将不会产生作用。不必担心Django会使用处理速度变慢。另外,当settings.DEBUG is False
的时候,staticfiles
将自动关闭。
models.py:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
from django.utils import timezone
from DjangoUeditor.models import UEditorField
# Create your models here.
#这个模型虽然准备好了,但是在后续没有用上,很可惜
class Under_bozhu(models.Model):
img_name = models.CharField(max_length=50)
img = models.CharField(max_length=200)
videos_name = models.CharField(max_length=50)
videos = models.CharField(max_length=200)
def __unicode__(self):
return self.img_name
#博客内容,这个是主要模型
class Bozhu(models.Model):
name = models.CharField(max_length=50)
title = models.CharField(max_length=200)
body = UEditorField(u'文章正文',height=300,width=800,default=u'',blank=True,
toolbars="mini",imagePath="aaa/%(basename)s_%(datetime)s.%",
filePath="bbb/",
)
pub_date = models.DateTimeField(default=timezone.now)
class Meta:
ordering = ('-pub_date',)
def __unicode__(self):
return self.title
其中的UeditorField是位于Github的一个开源项目。也就是一个百度开源的在线HTML编辑器,功能非常强大,像表格可以直接拖动调整单元格大小等。当然这个是UeditorField3,是git上的人修改的,具体地址:https://github.com/twz915/DjangoUeditor3/,它可以用在python3和python2上,也支持django1.10以上的版本。
UeditorField的源码由于许久未更新了,想要支持python3以及django1.9版本以上的好像都需要进行自行fork,进行版本的判定,然后在进行后续的操作,源码的地址是:https://github.com/zhangfisher/DjangoUeditor,可以自行参考。
然后在就可以使用命令,进行创建数据库和Django间的中介文件。
python manage.py makemigrations mysite
再同步更新数据库的内容。
python manage.py migrate
创建数据库的管理员帐号及密码。
python manage.py createsuperuser
#然后会分别要求输入帐号,邮箱,以及输入两次密码
创建玩数据库的管理员帐号,密码后,通过admin.site.register在admin.py上注册类
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.contrib import admin
from .models import Under_bozhu,Bozhu
# Register your models here.
admin.site.register(Under_bozhu)
admin.site.register(Bozhu)
通过开启Django自带的服务器,然后去网页中的/admin中添加一下测试数据。
因为设想一个正常的博客,网站主人最好可以直接在登录后,进行博客的撰写,而且,一个网站一般来说,需要可以联系到网站主人以便不时之需,所以我们可以使用第三方服务发送电子邮件,mailgun.com是一个不错的选择,它不仅提供了以网页界面的方式收发个人的邮件,而且还提供了API供程序使用,甚至还有python的Django专用模块,每个月还有一定的邮件的免费额度。其官网是:http://mailgun.com,自行注册,接受邮件的管理员邮箱需要开启认证哦,注意注册的时候,需要翻墙,不然验证码是看不到的,看不到自然也就无法注册成功,国外的网很多都这样。最后获得:
这个需要在settings.py中进行设置:
#Mailgun settings
EMAIL_BACKEND = 'django_mailgun.MailgunBackend'
MAILGUN_ACCESS_KEY = 'key-a0d********************'
MAILGUN_SERVER_NAME = 'sandbox47c*************6.mailgun.org'
因为登录页面,发送邮件的页面和登录后撰写博客的页面需要有表单,用来提交数据,所以我们在app下新建一个forms.py文件,并进行表单的设置:
#-*- coding:utf-8 -*-
from django import forms#导入forms模块
from mysite import models#从App导入Model
from django.utils import timezone
from captcha.fields import CaptchaField#验证码模块
class LoginForm(forms.Form):
user_name = forms.CharField(label='您的帐号',max_length=10)
user_pass = forms.CharField(label='您的密码',widget=forms.PasswordInput())
captcha = CaptchaField(label='验证码')
class WriteForm(forms.ModelForm):
class Meta:
model = models.Bozhu
fields = ['name','title','body','pub_date']
#引入models中的Bozhu,通过fields = []确定使用的字段
def __init__(self,*args,**kwargs):#对字段的名字进行初始化
super(WriteForm,self).__init__(*args,**kwargs)
self.fields['name'].label = '作者'
self.fields['title'].label = '文章标题'
self.fields['body'].label = '文章正文'
self.fields['pub_date'].label = '时间'
self.fields['pub_date'].initial = timezone.now
self.fields['name'].initial = 'hei6775'
#联系管理员的表单
class ContactForm(forms.Form):
CITYS = (
('BJ','北京'),('TJ','天津'),('SH','上海'),
)
contact_name = forms.CharField(label='您的姓名',max_length=50,initial='匿名者')
contact_place = forms.ChoiceField(label='您的所在省份',choices=CITYS)
contact_email = forms.EmailField(label='您的电子邮箱')
contact_message = forms.CharField(label='您的意见',widget=forms.Textarea)
这边有一个小问题就是联系管理员的表单的CITYS元组中第一个值没办法是中文,若是中文一直会报错,提示需要检查字段是否正确,如果用list好像更惨,两个都要是英文,这个问题暂时没有去解决。
其实表单中最重要的就是django的forms有两种窗体类Form和ModelForm
Form窗体类是自定义的窗体类,用于简单的验证或者暂时性的信息接受,一般和数据库存储无关,当然也是可以用于数据库的,但是我们有更适合用于数据库为主的ModelForm,它直接套用在Models.py中定义好的字段,直接使用,存储也会方便许多。
在templates中定义基本的模版base.html、header.html、footer.html:
header.html:
<!-- header.html -->
<nav class='navbar navbar-default'>
<div class='container-fluid'>
<div class='navbar-header'>
<div class='navbar-brand' align=center>
hei的博客
</div>
</div>
<ul class='nav navbar-nav'>
<li class='active'><a href='/'>Home</a></li>
{% if username %}
<li><a href='/write'>Writing blogs</a></li>
<li><a href='/logout'>注销</a></li>
{% else %}
<li><a href='/login'>登录</a></li>
{% endif %}
<li><a href='/postemail'>联系管理员</a></li>
<li><a href='/admin'>后台管理</a></li>
</ul>
</div>
</nav>
base.html是直接通过{% block *** %}{% endblock %}标志来填充其它网页信息的,{% block *** %}标志开始,{% endblock %}标志结束,然后CSS,JavaScript陡直直接使用bootstrap上的,通过{% include 'header.html' %}来加载header和footer,对网页的整体进行分割,更加容易实现对网页的布局,以及数据的处理:
<!-- base.html -->
<!DOCTYPE html>
{% load staticfiles %}
<html>
<head>
<meta charset='utf-8'>
<title>
{% block title %} {% endblock %}
</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
</head>
<body>
<div class='container-fluid'>
{% include 'header.html' %}
<div class='row'>
<div class='col-sm-4 col-md-4'>
<div class='panel panel-default'>
<div class='panel-heading'>
<h3>
MENU
</h3>
</div>
<div class='panel-body'>
<div class='list-group'>
<a href='/' class='list-group-item'>HOME</a>
<a href='/admin' class='list-group-item'>管理页面 </a>
<a href='http://news.qq.com/' class='list-group-item'>实时新闻</a>
<a href='http://v.qq.com/news/index.html' class='list-group-item'>电视新闻</a>
</div>
<script type="text/javascript" src="http://feedjit.com/serve/?vv=1515&tft=3&dd=0&wid=&pid=0&proid=0&bc=FFFFFF&tc=000000&brd1=012B6B&lnk=135D9E&hc=FFFFFF&hfc=2853A8&btn=C99700&ww=190&wne=6&srefs=0"></script><noscript><a href="http://feedjit.com/">Live Traffic Stats</a></noscript>
</div>
</div>
</div>
<div class='col-sm-8 col-md-8'>
<div class='panel panel-default'>
<div class='panel-heading'>
{% block headmessage %} {% endblock %}
</div>
<div class='panel-body'>
{% block content %} {% endblock %}
</div>
<div class='panel-footer'>
{% include 'footer.html' %}
</div>
</div>
</div>
</div>
</div>
</body>
</html>
footer.html:
<!-- footer.html -->
<hr>
{% load staticfiles %}
<img src="{% static "img/logo02.jpg" %}" width=100>
<em>Sorry,this picture is taken from the Internet<a href='http://baidu.com'>http://www.baidu.com</a>.You can send email to me.</em>
再在urls.py进行网址的映射:
#-*- coding:utf-8 -*-
"""myweb URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url,include
from django.contrib import admin
from mysite import views
from DjangoUeditor import urls as djud_urls
from django.conf import settings
from captcha import urls
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^ueditor/',include(djud_urls)),#编辑器所必需添加的路径
url(r'^captcha/',include('captcha.urls')),#验证码所必须添加的路径
url(r'^$',views.index),#主页
url(r'^login/',views.login),#登录页面
url(r'^logout/',views.logout),#注销
url(r'^write/',views.write),#撰写博客页面
url(r'^postemail/',views.post_email),#发送email给管理员的页面
url(r'^detail/(\d+)$',views.detail,name='detail-url'),#单篇博客的整体展示
]
if settings.DEBUG:#为了使用静态文件所添加的
from django.conf.urls.static import static
urlpatterns += static(settings.MEDIA_URL,document_root = settings.MEDIA_ROOT)
在views.py中处理视图函数:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
#导入网络方面的模块
from django.shortcuts import render
from django.http import HttpResponse,Http404,HttpResponseRedirect
from django.template.loader import get_template
from django.shortcuts import redirect
from django.contrib.auth.decorators import login_required
#导入认证模块
from django.contrib.auth.models import User
from django.contrib.auth import authenticate
from django.contrib import auth
#导入其它模块
from datetime import datetime
from django.contrib import messages
from django.core.mail import EmailMessage
#导入模型
from mysite import models
from mysite import forms
# Create your views here.
#主页显示
def index(request):
if request.user.is_authenticated:
username = request.user.username
messages.get_messages(request)
template = get_template('index.html')
posts = models.Bozhu.objects.all()
now = datetime.now()
html = template.render(context=locals(),request=request)
return HttpResponse(html)
#单篇博客处理
def detail(request,id):
if request.user.is_authenticated:
username = request.user.username
template = get_template('detail.html')
try:
detail = models.Bozhu.objects.get(id=id)
except:
return Http404
now = datetime.now()
html = template.render(context=locals(),request=request)
return HttpResponse(html)
#登录函数
def login(request):
if request.method == 'POST':
login_form = forms.LoginForm(request.POST)
if login_form.is_valid():
username = request.POST['user_name']
userpass = request.POST['user_pass']
user = authenticate(username=username,password=userpass)
if user is not None:
if user.is_active:
auth.login(request,user)
print 'success'
messages.add_message(request,messages.SUCCESS,'成功登录了')
return redirect('/')
else:
messages.add_message(request,messages.WARNING,'帐号或密码错误')
else:
messages.add_message(request,messages.WARNING,'帐号或密码错误')
else:
messages.add_message(request,messages.WARNING,'输入字符不合法')
else:
login_form = forms.LoginForm()
template = get_template('login.html')
html = template.render(context=locals(),request=request)
return HttpResponse(html)
#注销函数
@login_required
def logout(request):
auth.logout(request)
messages.add_message(request,messages.INFO,'成功退出')
return redirect('/')
#写博客模块
@login_required
def write(request):
if request.user.is_authenticated:
username = request.user.username
if request.method == 'POST':
write_form = forms.WriteForm(request.POST)
if write_form.is_valid():
messages.add_message(request,messages.INFO,'您的这篇博客已经保存...')
write_form.save()
return HttpResponseRedirect('/')
else:
messages.add_message(request,messages.WARNING,'请检查各个字段,暂时不支持暂存为草稿箱功能')
else:
write_form = forms.WriteForm()
#messages.add_message(request,messages.WARNING,'请检查各个字段,暂时不支持暂存为草稿箱功能')
template = get_template('post.html')
html = template.render(context=locals(),request=request)
return HttpResponse(html)
#联系管理员模块
def post_email(request):
if request.method == 'POST':
contact_form = forms.ContactForm(request.POST)
if contact_form.is_valid():
messages.add_message(request,messages.INFO,'感谢您的来信,我们会尽快处理')
contact_name = contact_form.cleaned_data['contact_name']
contact_place = contact_form.cleaned_data['contact_place']
contact_email = contact_form.cleaned_data['contact_email']
contact_message = contact_form.cleaned_data['contact_message']
email_body = u'''
网友昵称:{}
居住城市:{}
反映意见,如下:{}
'''.format(contact_name,contact_place,contact_message)
email = EmailMessage(
'来自网友的一封邮件',
email_body,
contact_email,
['913799761@qq.com']
)
email.send()
else:
messages.add_message(request,messages.WARNING,'请检查您输入的信息是否正确')
else:
contact_form = forms.ContactForm()
template = get_template('email.html')
html = template.render(context=locals(),request=request)
return HttpResponse(html)
有几点要说明一下:
- 个别页面,如注销页面,那肯定是必须要有登录才能访问注销,为了防止游客直接通过url访问本来需要登录操作后才能访问的页面,所以我们导入函数login_required,通过装饰起@在需要登录才能访问的页面的函数中加入@login_required,Django就会自动检测是否登录了。
from django.contrib.auth.decorators import login_required
- 在Django1.10版本以前,处理模版的网页显示是有些区别的,因为1.10及其以后的版本取消了上下文context:
#-*- conding:utf-8 -*- #1.10之前的版本 def example(request): template = get_template('example.html') example_blog = models.Blogs.objects.all() #关键就是下面三行 request_context = RequestContext(request) #context上下文 request_context.push(locals()) #直接使用locals(),会将当前内存中的所有局部变量使用字典类型打包起来 #但实际上这是一件有风险的事情,心怀不轨的人可能会利用这个漏洞 html = templte.render(request_context) return HttpResponse(html) #1.10及其以后的版本 def example(request): template = get_template('example.html') example_blog = models.Blogs.objects.all() #关键就是下面 html = templte.render(context=locals(),request=request) return HttpResponse(html)
那么就要来建设对应的网页了,我们需要:
- index.html
- detail.html
- email.html
- login.html
- post.html
index.html:
<!-- index.html -->
{% extends 'base.html' %}
{% block title %} 欢迎光临我的博客 {% endblock %}
{% block headmessage %}
<h3 style='font-family:楷体;'>本站文章列表</a>
{% endblock %}
{% block content %}
<div class='sdaasd'>
{% for message in messages %}
<div class='alert alert-{{ message.tags }}'>{{message}}</div>
{% endfor %}
{% for post in posts %}
<div class='panel panel-default'>
<div class='panel-heading'>
<p style='font-family:微软雅黑;font-size:14pt;font-weight:bold;'>
<a href='{% url "detail-url" post.id %}'>{{ post.title }}</a>
</p>
</div>
<div class='panel-body' style='background-color:#ffffdd'>
<p>
{{ post.body | truncatechars:100 | safe }}
</p>
</div>
<div class='panel-footer' style='background-color:#efefef'>
<p>
发布时间:{{ post.pub_date | date:"Y M d, h:m:s"}}
</p>
</div>
</div>
<br>
{% endfor %}
{% endblock %}
detail.html:
<!-- detail.html -->
{% extends 'base.html' %}
{% block title %} 欢迎光临我的博客 {% endblock %}
{% block headmessage %}
<h3 style='font-family:楷体;'>本站文章列表</a>
{% endblock %}
{% block content %}
<div class='sdaasd'>
{% for message in messages %}
<div class='alert alert-{{ message.tags }}'>{{message}}</div>
{% endfor %}
<div class='panel panel-default'>
<div class='panel-heading'>
<p style='font-family:微软雅黑;font-size:14pt;font-weight:bold;'>
<h3>{{ detail.title }}</h3>
</p>
</div>
<div class='panel-body' style='background-color:#ffffdd'>
<p>
<h5 align=right>{{detail.name}}</h5>
</p>
<p>
{{ detail.body }}
</p>
</div>
<div class='panel-footer' style='background-color:#efefef'>
<p>
发布时间:{{ detail.pub_date | date:"Y M d, h:m:s"}}
</p>
</div>
</div>
<br>
{% endblock %}
email.html:
<!-- email.html -->
{% extends "base.html" %}
{% block title %}的博客{% endblock %}
{% block headmessage %}请填写您宝贵的意见{% endblock%}
{% block content %}
<div class='sdaasd'>
{% for message in messages %}
<div class='alert alert-{{ message.tags }}'>{{message}}</div>
{% endfor %}
<div class='panel panel-default'>
<form name='write blog' action='.' method='POST'>
{% csrf_token %}
<table>
{{ contact_form.as_table }}
</table>
<br />
<input type='submit' value='发送'>
<input type='reset' value='清空'>
</form>
</div>
<br>
</div>
{% endblock %}
login.html:
<!-- login.html -->
{% extends 'base.html' %}
{% block title %} 登录 {% endblock %}
{% block headmessage %}
<h3 style='font-family:楷体;'>请登录您的帐号</a>
{% endblock %}
{% block content %}
<div class='container'>
{% for message in messages %}
<div class='alert alert-{{ message.tags }}'>{{message}}</div>
{% endfor %}
<div class='row'>
<div class='col-md-12'>
<div class='panel panel-dafault'>
<div class='panel-heading' align=left>
<h3>登录您的帐号密码</h3>
</div>
</div>
<form action='.' method='POST'>
{% csrf_token %}
<table>
{{ login_form.as_table }}
</table>
<br />
<input type='submit' value='登录'>
<input type='reset' value='清空'>
<br />
</form>
</div>
</div>
{% endblock %}
post.html:
<!-- post.html -->
{% extends "base.html" %}
{% block title %}hei6775的博客{% endblock %}
{% block headmessage %}请撰写您的博客文章{% endblock%}
{% block content %}
<div class='sdaasd'>
{% for message in messages %}
<div class='alert alert-{{ message.tags }}'>{{message}}</div>
{% endfor %}
<div class='panel panel-default'>
<form name='write blog' action='.' method='POST'>
{% csrf_token %}
<table>
{{write_form.media}}
{{ write_form.as_table }}
</table>
<br />
<input type='submit' value='保存到后台'>
<input type='reset' value='清空重新输入'>
</form>
</div>
<br>
</div>
{% endblock %}
到这里,差不多网站的基本内容就做完了,git到Github上,但是有些细节需要注意:
- 在需要提交信息的地方(即有按钮提交数据),需要在该网页模版中的<form>标签下加上标识符{% csrf_token %},这是一个Django为了防范网站CSRF(Cross-site request forgery,跨站请求伪造)攻击的机制,以确保黑客无法伪装为已被验证过的浏览器而盗取数据。
- 在模版中,form是通过view.py的实例化,然后通过locals()将变量打包到模版中,在模版中通过{{ form.as_table }}这个是以<tr><th>的标签格式的方式产生窗体的字段内容,但是不会产生<form>和</form>标签,提交按钮也不会自动生成,除此之外还可以使用form.as_p和form.as_ul来产生表单。
- 其次在写博客的网页模版中需要添加{{ write_form.media }},才能正确加载编辑器UeditorField。另外在Github上下载UeditorField时需要在www/myweb/目录下。
二、部署在阿里云服务器上。
首先我们需要在阿里云上购买一个服务器,阿里云官网,学生还可以优惠购机,最低9.9一个月,当然我选择的是ubuntu16.04版本,而且恰逢活动,9.9不仅仅享受半年的云服务器,还送一年域名,弹性公网 IP,负载均衡,云数据库 RDS,云数据库 Redis 版,对象存储 OSS。
点击云服务器,进入查看你的云服务器的IP。
可以在本机上下载Xshell和notepad+++,进行参数设置,连接服务器,进行操作。(怎么设置之前记录在我的博客中了)。
首先我们要做的就是买一个域名,然后网站备案,域名实名认证。
域名的购买:官网
网站的备案,跟着网页提示做备案申请:
域名也需要实名认证,否则域名无法解析:
域名实名认证后就需要进行解析的设置,因为我们的是一台云服务器而不是一个云虚拟主机所以我们不需要绑定到虚拟主机上。点击控制台——域名——解析。
我们需要添加两条解析,添加解析——记录类型(都填A)——主机记录(一个填@,另一个填www)——解析线路(默认就好)——记录值(填云服务器的公网IP),等待几分钟生效即可。
计划使用Apache作为Django的网页服务器,网上一般还会使用nginx。nginx比apache更加轻量级,nginx 处理请求是异步非阻塞的,而apache 则是阻塞型的,在高并发下nginx 能保持低资源低消耗高性能,apahce更加的稳定,模块也相对成熟。
安装Apache2,要让Apache2识别python程序执行的请求,还有一个模块mod_wsgi:
apt-get update
apt-get install apache2
apt-get install libapache2-mod-wsgi
然后安装pip组建管理程序和虚拟机环境程序virtualenv
apt-get install python-pip
apt-get install virtualenv
Linux操作系统中的Apache网页服务器会把网页放在/var/www/html中,所以我们一般也将网页放在/var/www下,到/var/www下创建一个虚拟环境并弃用,再使用git clone将Github上的项目下载一份下来:
cd /var/www
virtualenv VENV
source VENV/bin/activate
git clone https://********\myweb.git
cd myweb
pip install -r requirements.txt
在实际上,我们是通过网页服务器Apache把远程浏览器的请求传送到Django的程序中执行,再把执行后的结果通过Apache传回浏览器。说得具体一点就是即使我们主机没有执行python manage.py runserver,当用户端执行浏览器连接到主机后,Apache会把HTTP的request转给Django的配置文件wsgi.py,在这个设置文件中找到python解释器的相关环境设置,然后把正确的python程序交由解释器执行以产生结果。首先我们需要修改setting.py的SECRET_KEYS,将SECRET_KEYS的内容创建为/etc/secret_key.txt文件,并使用读取的方式获得SECRET_KEYS的内容,顺带把DEBUG设置为False,防止网页的调试信息出现在网页上。
# SECURITY WARNING: keep the secret key used in production secret!
with open('/etc/secret_key.txt') as f:
SECRET_KEY = f.read().strip()
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
要让Apache顺利地读取到wsgi.py,要对Apache的设置文件进行设置,此文件在/etc/apache2/site-available/000-default.conf文件中,
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
<VirtualHost *:80>
ServerName #填写你的域名
ServerAdmin #填写你的邮箱
ErrorLog ${APACHE_LOG_DIR}/error.log#错误的记录
CustomLog ${APACHE_LOG_DIR}/access.log combined#网站的浏览记录
Alias /static/ /var/www/myweb/staticfiles/#设置静态文件的位置
<Directory /var/www/myweb/staticfiles>#设置网站的最后收集的静态文件可以存取的权限
Require all granted
</Directory>
WSGIDaemonProcess myweb python-path=/var/www/myweb:/var/www/VENV/lib/python2.7/site-packages
#因为是虚拟环境,所以设置此网站的python所在位置以及Django网站的位置
WSGIProcessGroup myweb
WSGIScriptAlias / /var/www/myweb/myweb/wsgi.py
#设置wsgi.py的位置
</VirtualHost>
设置完以上配置,需要重新启动Apache:
service apache2 restart
最后需要执行收集静态文件的工作,语句如下:
python manage.py collectstatic
但是还是发现无法访问,打开DEBUG,显示db.sqlite3只能读取,无法写入。所以需要修改db.sqlite的权限:
chmod 757 /var/www/myweb/db.sqlite3
如果还有问题,可以把整个myweb的权限都修改:
chmod -R 757 /var/www/myweb
也可以修改myweb文件夹及该文件夹下的所有内容,其用户和所属群组是否均为www-data:www-data,当然在此之前你需要创建该用户啊。
chown -R www-data:www-data /var/www/myweb
在重启服务器,就可以访问了。