{{ intro.content }}
{{ intro.content }}

人生苦短,为什么我要用python?
#实战目标
使用Python3.7+Django2.2+sqlite实现一个企业门户网站先睹为快
TIP
该网站能满足大多数企业门户网站的需求
#学习前提
#环境搭建
#编程语言python3.7
Mac环境
在~/.bash_profile 文件中添加如下配置
IDE pycharm专业版
#虚拟环境 virtualenvwrapper
虚拟环境的主要作用是给不同的项目创建独立的运行环境,每一个虚拟环境可以有自己版本的依赖包
新建WORKON_HOME系统变量,值为一个有效的路径,用了存放虚拟环境
TIP
打开控制面板-系统和安全-系统-高级系统设置-环境变量-系统变量-点击新建
以管理员身份重新打开命令行
Mac 安装
使用
初始化项目
#创建项目的虚拟环境
用pycharm新建django项目
#完善项目目录结构
#pycharm 创建django应用
django项目目录结构解析
WEB原理解析和MVC介绍
#WEB原理解析
#MVC介绍
#静态页面路由配置
#添加View类
在apps.basic.views添加处理路由的View
TIP
Django中view分为CBV(class base view)和FBV(function base view),推荐CBV
#添加html页面
在templates文件夹新新建一个index.html静态页面
#配置路由
在urls.py文件中添加
静态资源处理
#在html页面中使用静态资源
copy前端准备好的模版文件(html)到templates文件夹中
#添加静态资源
copy前端准备好的静态资源文(css,js,image)件到static文件中
#配置静态文件查找路径配置
在settings.py中添加如下配置
模版的使用
#定义模版
配置其他路由和跳转
#View类
配置路由
TIP
注意detail路由的配置是为了传递参数到view中
#配置跳转
记录导航选中状态
在模版中根据标识设置class
#模型定义
安装Pillow
由于模型中需要定以图片的上传,所以需要安装
pip install Pillow -i https://mirrors.aliyun.com/pypi/simple/
定义共同父类
from datetime import datetime from django.db import models # 定义共同类 class BaseModel(models.Model): add_time = models.DateTimeField(verbose_name="添加时间",default=datetime.now) class Meta: abstract = True #不生成表
定义站点配置模型
class Config(BaseModel): name = models.CharField(verbose_name="站点名称", max_length=100) logo = models.ImageField(verbose_name="站点logo", max_length=300, upload_to="config/logo/%Y/%m") url = models.CharField(verbose_name="站点连接", max_length=100) wx_qr_code = models.ImageField(verbose_name="微信二维码",max_length=300,upload_to="config/wx/%Y/%m") tel = models.CharField(verbose_name="联系电话",max_length=20) hours = models.CharField(verbose_name="营业时间", max_length=40) mail = models.CharField(verbose_name="电子邮件", max_length=300) icp = models.CharField(verbose_name="备案号", max_length=50) class Meta: verbose_name = "站点配置" verbose_name_plural = verbose_name def __str__(self): return self.name
数据库表操作和创建管理员
makemigrations
migrate
createsuperuser
后台管理配置
#注册模型
在应用的admin.py文件中
#admin.py from django.contrib import admin from apps.basic.models import Config class ConfigAdmin(admin.ModelAdmin): pass admin.site.register(Config,ConfigAdmin)
#配置中文和时区
在settings.py中配置中文和时区
#settings.py LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai' USE_TZ = False
#修改网页title和站点header
在应用的admin.py文件中
#admin.py #修改网页title和站点header admin.site.site_title = "PyCMS后台管理" admin.site.site_header = "PyCMS"
#修改应用的中文名称
在应用的apps.py文件中修改应用的中文名称
#apps.py class BasicConfig(AppConfig): name = 'apps.basic' verbose_name = "站点基本"
#配置上传资源路径
在settings.py中配置上传资源路径
#settings.py MEDIA_URL = "/media/" MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
#自定义表单
在应用的admin.py文件中,在管理器类中添加 fields 属性来定义表单要显示的字段
#admin.py
from django.contrib import admin
from apps.basic.models import Config
class ConfigAdmin(admin.ModelAdmin):
fields = ('name','logo','url','wx_qr_code','tel','hours','mail','icp')
# Register your models here.
admin.site.register(Config,ConfigAdmin)
#列表显示
在应用的admin.py文件中,在管理器类中添加 list_display 属性来定义列表要显示的字段
#admin.py
from django.contrib import admin
from apps.basic.models import Config
class ConfigAdmin(admin.ModelAdmin):
fields = ('name','logo','url','wx_qr_code','tel','hours','mail','icp')
list_display = ('name','url','tel','hours','mail','icp')
# Register your models here.
admin.site.register(Config,ConfigAdmin)admin登陆添加验证码
pip3 install django-multi-captcha-admin pip3 install django-simple-captcha
#settings.py
INSTALLED_APPS = [
'multi_captcha_admin',#需要在django.contrib.admin前添加
....
'captcha',#验证码模块
]
MULTI_CAPTCHA_ADMIN = {
'engine': 'simple-captcha',
}
#urls.py
from django.urls import path, include
...
url(r'^captcha/', include('captcha.urls')),
migrate
#分配数据到模版展示
#获取和分配数据(objects.get()获取一条)
# views.py
from apps.basic.models import Config
class IndexView(View):
def get(self, request, *args, **kwargs):
# 获取一条数据对象
config = Config.objects.get()
return render(request, 'index.html',{
'currentPage':'index',
'config':config #将对象分配到模版
})
#展示数据
{{ config.tel }}({{ config.hours }})
友情连接
#模型定义
class Link(BaseModel): name = models.CharField(verbose_name="友情连接名称", max_length=100) url = models.CharField(verbose_name="友情连接地址", max_length=300) class Meta: verbose_name = "友情连接" verbose_name_plural = verbose_name def __str__(self): return self.name
TIP
模型注册,表迁移,数据同步参考站点配置模型
#获取和分配数据(objects.all()获取所有)
#views.py
class IndexView(View):
def get(self, request, *args, **kwargs):
# 获取一条数据对象
config = Config.objects.get()
# 获取友情链接
links = Link.objects.all()
return render(request, 'index.html',{
'currentPage':'index',
'config':config, #将对象分配到模版
'links':links
})
#展示数据
{% for link in links %}
{{ link.name }}
{% endfor %}
TIP
Link.objects.all()返回的是一个QuerySet,需要在模版中通过for in来遍历得到每一对象
#首页轮播图
#模型定义
class Carousel(BaseModel): title = models.CharField(verbose_name="轮播图名称", max_length=100) image = models.ImageField(verbose_name="轮播图图片", max_length=300, upload_to="carousel/%Y/%m") desc = models.CharField(verbose_name="轮播图描述", max_length=100) class Meta: verbose_name = "首页轮播图" verbose_name_plural = verbose_name def __str__(self): return self.title
TIP
模型注册,表迁移,数据同步,获取和分配数数据,展示数据 参考友情链接模型
#产品
#模型定义
class Product(BaseModel): name = models.CharField(verbose_name="产品名称", max_length=100) desc = models.TextField(verbose_name="产品描述", max_length=300) icon = models.ImageField(verbose_name="产品图标", max_length=300, upload_to="product/icon/%Y/%m") url = models.CharField(verbose_name="产品连接", max_length=100) image = models.ImageField(verbose_name="产品封面",max_length=300,upload_to="product/post/%Y/%m") is_show_index = models.BooleanField(verbose_name="是否显示在首页",default=False) class Meta: verbose_name = "产品" verbose_name_plural = verbose_name def __str__(self): return self.name
#数据获取(filter筛选)
#views.py # 获取首页需要的产品 products = Product.objects.filter(is_show_index=True)
TIP
#服务
#模型定义
# 服务 class Service(BaseModel): name = models.CharField(verbose_name="服务名称", max_length=100) desc = models.TextField(verbose_name="服务描述", max_length=300) image = models.ImageField(verbose_name="服务封面",max_length=300,upload_to="service/post/%Y/%m") class Meta: verbose_name = "服务" verbose_name_plural = verbose_name def __str__(self): return self.name
TIP
模型注册,表迁移,数据同步,获取和分配数数据,展示数据 参考友情链接模型
#产品页面开发
TIP
参考首页开发
#动态页面开发
#动态模型
class News(BaseModel): name = models.CharField(verbose_name="动态标题", max_length=100) desc = models.TextField(verbose_name="动态描述", max_length=300) intro = models.TextField(verbose_name="动态简介", max_length=300) content = models.TextField(verbose_name="动态内容", max_length=300) read_nums = models.IntegerField(verbose_name="阅读人数", default=0) post = models.ImageField(verbose_name="封面图片",max_length=300,upload_to="news/post/%Y/%m") image = models.ImageField(verbose_name="详情图片", max_length=300, upload_to="news/detail/%Y/%m") class Meta: verbose_name = "动态" verbose_name_plural = verbose_name def __str__(self): return self.name
#安装分页应用
pip3 install django-pure-pagination
#settings.py INSTALLED_APPS = [ ... 'pure_pagination',#分页配置 ]
#settings.py
# 分页相关配置
PAGINATION_SETTINGS = {
'PAGE_RANGE_DISPLAYED': 6,
'MARGIN_PAGES_DISPLAYED': 2,
'SHOW_FIRST_PAGE_WHEN_INVALID': True,
}
#在views.py中使用分页应用
from pure_pagination import Paginator, EmptyPage, PageNotAnInteger
class NewsView(View):
def get(self, request, *args, **kwargs):
# 获取一条数据对象
config = Config.objects.get()
# 获取友情链接
links = Link.objects.all()
# 按添加时间倒序获取所有的动态
all_news = News.objects.order_by("-add_time")
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
p = Paginator(all_news, per_page=2, request=request)
news = p.page(page)
return render(request, 'news.html',{
'currentPage': 'news',
'config': config,
'links': links,
'news':news
})
TIP
#在模版中使用分页
TIP
分页对象需要遍历对象上的object_list
{% if news.has_previous %} 上一页 {% endif %} {% for page in news.pages %} {% if page %} {% ifequal page news.number %} {{ page }} {% else %} {{ page }} {% endifequal %} {% else %} ... {% endif %} {% endfor %} {% if news.has_next %} 下一页 {% endif %}
#动态详情页面开发
#获取动态并分配给模版
class NewsDetailView(View):
def get(self, request,news_id, *args, **kwargs):
# 获取一条数据对象
config = Config.objects.get()
# 获取友情链接
links = Link.objects.all()
# 获取动态
news = News.objects.get(id=int(news_id))
# 修改动态的阅读人数
news.read_nums += 1
news.save()
return render(request, 'newsDetail.html',{
'currentPage': 'news',
'config': config,
'links': links,
'news':news
})
TIP
#关于我们页面开发
#定义模型
# 公司简介 class Intro(BaseModel): content = models.TextField(verbose_name="简介内容", max_length=300) image = models.ImageField(verbose_name="简介图片", max_length=300, upload_to="intro/%Y/%m") class Meta: verbose_name = "公司简介" verbose_name_plural = verbose_name def __str__(self): return self.content # 发展历程 class Timeline(BaseModel): label = models.CharField(verbose_name="历程标签", max_length=100) desc = models.TextField(verbose_name="历程描述", max_length=100) image = models.ImageField(verbose_name="历程图片", max_length=300, upload_to="timeline/%Y/%m") class Meta: verbose_name = "发展历程" verbose_name_plural = verbose_name def __str__(self): return self.label
TIP
模型注册,表迁移,数据同步,获取和分配数数据, 参考友情链接模型
#数据展示
{% for intro in intros %}
{% if forloop.counter|divisibleby:2 %}
{{ intro.content }}
{{ intro.content }}
{% else %}
{{ intro.content }}
{% endif %}
{% endfor %}
TIP
#配置错误页面
#准备相关的错误页面
#修改settings.py文件
# 开发环境配置 # DEBUG = True # ALLOWED_HOSTS = [] # 线上环境配置 DEBUG = False ALLOWED_HOSTS = ['*'] # 开发环境配置,静态文件查找路径配置 # STATICFILES_DIRS = [ # os.path.join(BASE_DIR, 'static'), # ] # 线上环境配置 STATIC_ROOT = os.path.join(BASE_DIR, 'static')
#修改urls.py文件
from project.settings import STATIC_ROOT urlpatterns = [ ... # 静态资源访问的路由配置(线上配置only) url(r'^static/(?P.*)$', serve, {"document_root": STATIC_ROOT}), ]
#收集项目所需依赖文件
pip3 freeze > requirements.txt
#部署上线
#购买云服务器(以阿里云为例)
#开放云服务器的端口
在云服务器对应的实例中安全组规则中添加
允许 自定义 TCP 80/80 IPv4地址段访问 0.0.0.0/0 允许 自定义 TCP 8000/8000 IPv4地址段访问 0.0.0.0/0
#登陆服务器
#用pycharm上传代码
#环境安装
#安装python3.7
yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel gcc gcc-c++ openssl-devel libffi-devel python-devel mariadb-devel
wget https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tgz tar -xzvf Python-3.7.3.tgz -C /tmp cd /tmp/Python-3.7.3/
./configure --prefix=/usr/local make make install #这一步比较耗时
ln -s /usr/local/bin/python3.7 /usr/bin/python3 ln -s /usr/local/bin/pip3.7 /usr/bin/pip3
#安装新版sqlite
wget https://www.sqlite.org/2019/sqlite-autoconf-3270200.tar.gz tar -zxvf sqlite-autoconf-3270200.tar.gz -C /tmp cd /tmp/sqlite-autoconf-3270200/
./configure --prefix=/usr/local make make install #这一步比较耗时
#如果文件已经存在则备份 mv /usr/bin/sqlite3 /usr/bin/sqlite3_old #建立软链接 ln -s /usr/local/bin/sqlite3 /usr/bin/sqlite3
export LD_LIBRARY_PATH="/usr/local/lib"
source ~/.bashrc
#安装virtualenvwrapper
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3 yum install python-setuptools python-devel pip3 install virtualenvwrapper
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3 export WORKON_HOME=$HOME/.virtualenvs source /usr/local/bin/virtualenvwrapper.sh
source ~/.bashrc
TIP
如果出现找不到文件,可以使用以下命令查找文件的位置
sudo find / -name 文件名
mkvirtualenv -p python3 pycms
workon pycms
注意,需要把requirements.txt文件上传到服务器之后运行
pip3 install -r requirements.txt
确保settings.py文件中有以下配置
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
然后运行命令
python3 manage.py collectstatic
在项目的根目录下执行
python3 manage.py runserver 0.0.0.0:80
#域名解析
设置记录类型为A,设置记录值为对应的外网ip
#uwsgi+nignx部署项目
#安装uwsgi
web 容器,拉起项目
pip3 install uwsgi
在项目的根目录运行
#项目名称.wsgi uwsgi --http :8000 --module project.wsgi
新建 项目根目录/config/uwsgi.ini
# uwsgi.ini file [uwsgi] # 表示需要操作的目录,也就是项目的目录 chdir = /root/pycms # Django的wsgi file # wsgi文件的路径,名称和项目的应用名称一直 module = project.wsgi # process-related settings # master master = true # maximum number of worker processes # 进程数 processes = 10 # the socket (use the full path to be safe) socket = 127.0.0.1:8000 # chmod-socket = 664 # clear environment on exit vacuum = true # 虚拟环境的目录 virtualenv = /root/.virtualenvs/pycms # 运行log存放文件 logto = /tmp/uwsgi.log
workon pycms # -d表示后台运行 uwsgi -d -i 项目根目录/config/uwsgi.ini
ps aux|grep uwsgi
TIP
注意:用配置文件启动的uwsgi不能直接在浏览器中访问
netstat -lpnt
killall -9 uwsgi
#安装nginx
nginx主要用来反向代理,端口转发
sudo yum install epel-release sudo yum install nginx
sudo systemctl start nginx
# the upstream component nginx needs to connect to
upstream django {
server 127.0.0.1:8000; #转发到的端口,同uwsig配置的端口一直
}
# configuration of the server
server {
# 监听的端口
listen 80;
# 域名或者ip地址,如果共存用空格隔开
server_name 你的ip地址;
charset utf-8;
# 上传文件大小设置
client_max_body_size 75M;
location /media {
alias 项目根目录/media; # 指向django的media目录
}
location /static {
alias 项目根目录/static; # 指向django的static目录
}
# 非静态资源请求转发到django
location / {
uwsgi_pass django;
include uwsgi_params; # the uwsgi_params file you installed
}
}
sudo ln -s pycms_nginx.conf /etc/nginx/conf.d/
user root
sudo systemctl start nginx
sudo systemctl restart nginx
#附录:pycharm常用调试技巧