人生苦短,为什么我要用python?
- 首先让我们来看一个2019年最新的编程语言权威排行榜github octoverse
- 既然python如此流行,谁能告诉我why?易上手跨平台高薪水应用广TIPpython除了不能生孩子,啥都能干,如WEB开发,网络爬虫,数据分析,大数据,人工智能,服务器运维,自动化测试...
#实战目标
使用Python3.7+Django2.2+sqlite实现一个企业门户网站先睹为快
TIP
该网站能满足大多数企业门户网站的需求
#学习前提
- 对编程感兴趣
- 了解python的基础语法
- 了解html/css/js
#环境搭建
#编程语言python3.7
- windows环境下载安装包执行下载的安装包,注意在安装时选中Add Python 3.7 to PATH
Mac环境
- 下载安装文件
- 执行下载的安装包
- 配置
在~/.bash_profile 文件中添加如下配置
IDE pycharm专业版
- windows环境下载pycharm Professional 安装包
#虚拟环境 virtualenvwrapper
虚拟环境的主要作用是给不同的项目创建独立的运行环境,每一个虚拟环境可以有自己版本的依赖包
- Windows 安装在命令行执行
新建WORKON_HOME系统变量,值为一个有效的路径,用了存放虚拟环境
TIP
打开控制面板-系统和安全-系统-高级系统设置-环境变量-系统变量-点击新建
- 双击python的安装路径Scriptsvirtualenvwrapper.bat文件
以管理员身份重新打开命令行
Mac 安装
- 在终端执行以下命令
使用
初始化项目
#创建项目的虚拟环境
用pycharm新建django项目
- 在新建面板的左侧选择django项目
- 在Location中指定项目所在的位置
- 在Existing interpreter 中指定项目的python解释器在Virtualenv Environment中的Interpreter 中选择创建的虚拟环境python所在的路径TIP一般Windows用的这个路径为 虚拟环境存放目录虚拟环境名称Scriptspython.exe一般Mac用户的这个路径为 用户名/.virtualenvs/虚拟环境名称/bin/python
- 选中Enable Django admin
#完善项目目录结构
- 在项目目录下新建media文件夹用来存放上传资源
- 在项目目录下新建static文件夹用来存放静态资源
- 在项目目录下新建apps包用来存放应用
#pycharm 创建django应用
- 打开 Tools->Run manage.py task
- 在终端执行
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中
#配置跳转
- 直接跳转
记录导航选中状态
- 在view中传递当前页面标识到模版
在模版中根据标识设置class
首页产品动态关于
#模型定义
安装Pillow
由于模型中需要定以图片的上传,所以需要安装
pip install Pillow -i https://mirrors.aliyun.com/pypi/simple/
定义共同父类
from datetime import datetimefrom 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
数据库表操作和创建管理员
- 打开Tools->Run manage.py task
- 生成表迁移
makemigrations
- 将表迁移同步到数据库
migrate
- 创建超级用户
createsuperuser
后台管理配置
#注册模型
在应用的admin.py文件中
#admin.pyfrom django.contrib import adminfrom apps.basic.models import Configclass ConfigAdmin(admin.ModelAdmin): passadmin.site.register(Config,ConfigAdmin)
#配置中文和时区
在settings.py中配置中文和时区
#settings.pyLANGUAGE_CODE = 'zh-hans'TIME_ZONE = 'Asia/Shanghai'USE_TZ = False
#修改网页title和站点header
在应用的admin.py文件中
#admin.py#修改网页title和站点headeradmin.site.site_title = "PyCMS后台管理"admin.site.site_header = "PyCMS"
#修改应用的中文名称
在应用的apps.py文件中修改应用的中文名称
#apps.pyclass BasicConfig(AppConfig): name = 'apps.basic' verbose_name = "站点基本"
#配置上传资源路径
在settings.py中配置上传资源路径
#settings.pyMEDIA_URL = "/media/"MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
#自定义表单
在应用的admin.py文件中,在管理器类中添加 fields 属性来定义表单要显示的字段
#admin.pyfrom django.contrib import adminfrom apps.basic.models import Configclass 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.pyfrom django.contrib import adminfrom apps.basic.models import Configclass 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-adminpip3 install django-simple-captcha
- 配置
#settings.pyINSTALLED_APPS = [ 'multi_captcha_admin',#需要在django.contrib.admin前添加 .... 'captcha',#验证码模块]MULTI_CAPTCHA_ADMIN = { 'engine': 'simple-captcha',}
- 添加路由
#urls.pyfrom django.urls import path, include...url(r'^captcha/', include('captcha.urls')),
- 数据迁移
migrate
#分配数据到模版展示
#获取和分配数据(objects.get()获取一条)
# views.pyfrom apps.basic.models import Configclass 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.pyclass 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
- 模型注册,表迁移,数据同步,分配数数据,展示数据 参考友情链接模型
- 数据获取使用filter进行筛选,filter返回结果也是一个QuerySet,在模版中需要用for in
#服务
#模型定义
# 服务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
#安装分页应用
- 参考 django-pure-pagination
- 在虚拟环境中安装
pip3 install django-pure-pagination
- 在settings.py中INSTALLED_APPS配置
#settings.pyINSTALLED_APPS = [ ... 'pure_pagination',#分页配置]
- 在settings.py中配置分页参数
#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, PageNotAnIntegerclass 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
- objects.order_by()是排序
- 以上代码生成的news是一个分页对象
#在模版中使用分页
- 动态遍历
{% for item in news.object_list %}
{{ item.name }}
{{ item.desc }}[详细]
阅读 {{ item.read_nums }} 发布时间:{{ item.add_time }}
{% endfor %}
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
- objects.get(id=int(news_id))是根据id获取数据
- 模版数据展示参考之前模型
#关于我们页面开发
#定义模型
# 公司简介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
- 在模版中遍历时可以用{% if forloop.counter|divisibleby:2 %}来判断当前是否是偶数
- 成长历程的遍历同理
#配置错误页面
#准备相关的错误页面
- 404.html
#修改settings.py文件
# 开发环境配置# DEBUG = True# ALLOWED_HOSTS = []# 线上环境配置DEBUG = FalseALLOWED_HOSTS = ['*']# 开发环境配置,静态文件查找路径配置# STATICFILES_DIRS = [# os.path.join(BASE_DIR, 'static'),# ]# 线上环境配置STATIC_ROOT = os.path.join(BASE_DIR, 'static')
#修改urls.py文件
from project.settings import STATIC_ROOTurlpatterns = [ ... # 静态资源访问的路由配置(线上配置only) url(r'^static/(?P.*)$', serve, {"document_root": STATIC_ROOT}),]
#收集项目所需依赖文件
pip3 freeze > requirements.txt
#部署上线
#购买云服务器(以阿里云为例)
- 购买时操作系统选择CentOS 7.7 64位
- 记录远程连接密码,在远程连接时用
- 重置实例密码,该密码是登陆系统时使用
#开放云服务器的端口
在云服务器对应的实例中安全组规则中添加
允许自定义 TCP80/80 IPv4地址段访问0.0.0.0/0 允许自定义 TCP8000/8000IPv4地址段访问0.0.0.0/0
#登陆服务器
- 方法一:远程连接后登陆系统,用户名:root 密码:重置的实例密码
- 方法二(推荐):在本机终端通过 ssh root@服务器公共ip 登陆,登陆需要输入实例密码,注意windows用户需要安装xshell
#用pycharm上传代码
- Tools->Deployment->Configuration...
- Add->SFTP
- 配置Connection连接远程服务器
- 配置Mappings,本地项目的文件和远程服务的目录对应,注意远程服务器的目录需要自己建立
- 右击需要上传的项目目录->deployment->upload,注意如果只上传某一个文件或目录则只右击需要上传的文件或者目录
#环境安装
#安装python3.7
- 1.安装依赖
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
- 2.下载源码
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/
- 3.把Python3.7安装到 /usr/local 目录
./configure --prefix=/usr/localmakemake install #这一步比较耗时
- 4.更改/usr/bin/python链接
ln -s /usr/local/bin/python3.7 /usr/bin/python3ln -s /usr/local/bin/pip3.7 /usr/bin/pip3
#安装新版sqlite
- 1.下载源码
wget https://www.sqlite.org/2019/sqlite-autoconf-3270200.tar.gztar -zxvf sqlite-autoconf-3270200.tar.gz -C /tmp cd /tmp/sqlite-autoconf-3270200/
- 2.把sqlite安装到 /usr/local 目录
./configure --prefix=/usr/localmakemake install #这一步比较耗时
- 3.建立软链接
#如果文件已经存在则备份mv /usr/bin/sqlite3 /usr/bin/sqlite3_old#建立软链接ln -s /usr/local/bin/sqlite3 /usr/bin/sqlite3
- 4.修改 ~/.bashrc文件
export LD_LIBRARY_PATH="/usr/local/lib"
- 5.从新加载~/.bashrc文件
source ~/.bashrc
#安装virtualenvwrapper
- 1.安装
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3yum install python-setuptools python-develpip3 install virtualenvwrapper
- 2.修改~/.bashrc文件
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3export WORKON_HOME=$HOME/.virtualenvssource /usr/local/bin/virtualenvwrapper.sh
- 3.从新加载~/.bashrc文件
source ~/.bashrc
TIP
如果出现找不到文件,可以使用以下命令查找文件的位置
sudo find / -name 文件名
- 4.新建虚拟环境
mkvirtualenv -p python3 pycms
- 5.进入虚拟环境
workon pycms
- 6.安装pip包
注意,需要把requirements.txt文件上传到服务器之后运行
pip3 install -r requirements.txt
- 7.拉取所有需要的static file 到同一个目录
确保settings.py文件中有以下配置
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
然后运行命令
python3 manage.py collectstatic
- 8.启动项目
在项目的根目录下执行
python3 manage.py runserver 0.0.0.0:80
- 9.通过公网ip地址访问项目
#域名解析
设置记录类型为A,设置记录值为对应的外网ip
#uwsgi+nignx部署项目
#安装uwsgi
web 容器,拉起项目
- 1.安装
pip3 install uwsgi
- 2.测试
在项目的根目录运行
#项目名称.wsgiuwsgi --http :8000 --module project.wsgi
- 3.配置
新建 项目根目录/config/uwsgi.ini
# uwsgi.ini file[uwsgi]# 表示需要操作的目录,也就是项目的目录chdir = /root/pycms# Django的wsgi file# wsgi文件的路径,名称和项目的应用名称一直module = project.wsgi# process-related settings# mastermaster = 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 exitvacuum = true# 虚拟环境的目录virtualenv = /root/.virtualenvs/pycms# 运行log存放文件logto = /tmp/uwsgi.log
- 4.启动uwsgi
workon pycms# -d表示后台运行uwsgi -d -i 项目根目录/config/uwsgi.ini
- 5.查看启动
ps aux|grep uwsgi
TIP
注意:用配置文件启动的uwsgi不能直接在浏览器中访问
- 6.查看端口
netstat -lpnt
- 6.关闭uwsgi
killall -9 uwsgi
#安装nginx
nginx主要用来反向代理,端口转发
- 1.安装
sudo yum install epel-releasesudo yum install nginx
- 2.启动
sudo systemctl start nginx
- 3.新建 项目根目录/config/nginx.conf
# the upstream component nginx needs to connect toupstream django {server 127.0.0.1:8000; #转发到的端口,同uwsig配置的端口一直}# configuration of the serverserver {# 监听的端口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目录}# 非静态资源请求转发到djangolocation / { uwsgi_pass django; include uwsgi_params; # the uwsgi_params file you installed}}
- 4.将该配置文件加入到nginx的启动配置文件中
sudo ln -s pycms_nginx.conf /etc/nginx/conf.d/
- 修改 /etc/nginx/nginx.conf
user root
- 6.启动nginx
sudo systemctl start nginx
- 7.重启nigx
sudo systemctl restart nginx
#附录:pycharm常用调试技巧
- 在需要调试的代码对应的行号处单击设置断点
- 右键以debug模式运行代码,代码会暂停在端点处,常见调试按钮F8(第二个按钮) 执行下一步F7(第三个按钮) 进入函数内部Shift+F8(第六个按钮) 跳出函数option + F9(最后一个按钮) 直接跳转到下一个断点处