时间:2023-07-31 17:26:01 点击次数:8
人生苦短,为什么我要用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 PATHMac环境
下载安装文件执行下载的安装包配置在~/.bash_profile 文件中添加如下配置
IDE pycharm专业版
windows环境下载pycharm Professional 安装包Mac环境下载pycharm Professional 安装包#虚拟环境 virtualenvwrapper
虚拟环境的主要作用是给不同的项目创建独立的运行环境,每一个虚拟环境可以有自己版本的依赖包
Windows 安装在命令行执行新建WORKON_HOME系统变量,值为一个有效的路径,用了存放虚拟环境
TIP
打开控制面板-系统和安全-系统-高级系统设置-环境变量-系统变量-点击新建
双击python的安装路径\Scripts\virtualenvwrapper.bat文件以管理员身份重新打开命令行
Mac 安装
在终端执行以下命令使用
初始化项目
#创建项目的虚拟环境
用pycharm新建django项目
在新建面板的左侧选择django项目在Location中指定项目所在的位置在Existing interpreter 中指定项目的python解释器在Virtualenv Environment中的Interpreter 中选择创建的虚拟环境python所在的路径TIP一般Windows用的这个路径为 虚拟环境存放目录\虚拟环境名称\Scripts\python.exe一般Mac用户的这个路径为 用户名/.virtualenvs/虚拟环境名称/bin/python选中Enable Django admin打开 Run->Run project 运行项目来测试django是否安装成功django 参考文档: Djano 官网 Djano 中文文档#完善项目目录结构
在项目目录下新建media文件夹用来存放上传资源在项目目录下新建static文件夹用来存放静态资源在项目目录下新建apps包用来存放应用#pycharm 创建django应用
打开 Tools->Run manage.py task在终端执行django项目目录结构解析
WEB原理解析和MVC介绍
#WEB原理解析
客户端用户发送请求服务器解析请求,计算数据并返回给客户端客户端解析返回的数据#MVC介绍
客户端用户发送请求模型框架负责路由解析,根据路由寻找对应的控制器(Controller)和行为(action)行为(action)调用相关的模型(Model)进行数据操作行为(action)根据数据操作的结果调用视图(View)进行页面的渲染,输出到客户端#静态页面路由配置
#添加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
<li class="layui-nav-item {% ifequal currentPage index %}layui-this{% endifequal %}"><a href="{% url index %}">首页</a></li> <li class="layui-nav-item {% ifequal currentPage product %}layui-this{% endifequal %}"><a href="{% url product %}">产品</a></li> <li class="layui-nav-item {% ifequal currentPage news %}layui-this{% endifequal %}"><a href="{% url news %}">动态</a></li> <li class="layui-nav-item {% ifequal currentPage about %}layui-this{% endifequal %}"><a href="{% url about %}">关于</a></li>#模型定义
安装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数据库表操作和创建管理员
打开Tools->Run manage.py task生成表迁移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 #将对象分配到模版 })#展示数据
普通数据展示<!--base.html--> <p class="contact-top"><i class="layui-icon layui-icon-cellphone"></i>{{ config.tel }}({{ config.hours }})</p> 上传图片数据展示模版中使用<!--base.html--> <div class="layui-col-sm2 layui-col-lg1"><img src="{{ config.wx_qr_code.url }}"></div> 在urls.py中配置上传文件请求路由# urls.py from django.views.static import serve from project.settings import MEDIA_ROOT urlpatterns = [ ... # 上传文件访问的路由配置 url(r^media/(?P<path>.*)$, serve, {"document_root": MEDIA_ROOT}), ]友情连接
#模型定义
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.nameTIP
模型注册,表迁移,数据同步参考站点配置模型
#获取和分配数据(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 })#展示数据
<!--base.html--> {% for link in links %} <a href="{{ link.url }}" target="_blank">{{ link.name }}</a> {% 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.titleTIP
模型注册,表迁移,数据同步,获取和分配数数据,展示数据 参考友情链接模型
#产品
#模型定义
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.nameTIP
模型注册,表迁移,数据同步,获取和分配数数据,展示数据 参考友情链接模型
#产品页面开发
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.py INSTALLED_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, 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
objects.order_by()是排序以上代码生成的news是一个分页对象#在模版中使用分页
动态遍历 {% for item in news.object_list %} <div class="layui-col-lg6 content"> <div> <div class="news-img"><a href="{% url detail item.id %}"><img src="{{ item.post.url }}"></a></div><div class="news-panel"> <strong><a href="{% url detail item.id %}">{{ item.name }}</a></strong> <p class="detail"><span>{{ item.desc }}</span><a href="{% url detail item.id %}">[详细]</a></p> <p class="read-push">阅读 <span>{{ item.read_nums }}</span> 发布时间:<span>{{ item.add_time }}</span></p> </div> </div> </div> {% endfor %}TIP
分页对象需要遍历对象上的object_list
分页器渲染 <div class="page-list"> <div class="layui-box layui-laypage layui-laypage-molv" id="layui-laypage-1"> {% if news.has_previous %} <a href="?{{ news.previous_page_number.querystring }}" class="layui-laypage-next">上一页</a> {% endif %} {% for page in news.pages %} {% if page %} {% ifequal page news.number %} <span class="layui-laypage-curr"><em class="layui-laypage-em" style="background-color:#2db5a3;"></em><em>{{ page }}</em></span> {% else %} <a href="?{{ page.querystring }}" class="page">{{ page }}</a> {% endifequal %} {% else %} <a href="javascript:;" class="none">...</a> {% endif %} {% endfor %} {% if news.has_next %} <a href="?{{ news.next_page_number.querystring }}" class="layui-laypage-next">下一页</a> {% endif %} </div> </div>#动态详情页面开发
#获取动态并分配给模版
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.labelTIP
模型注册,表迁移,数据同步,获取和分配数数据, 参考友情链接模型
#数据展示
{% for intro in intros %} {% if forloop.counter|divisibleby:2 %} <div class="content"> <div class="layui-inline panel p_block"> <p>{{ intro.content }}</p> </div><div class="layui-inline img"><img src="{{ intro.image.url }}"></div> <p class="p_hidden">{{ intro.content }}</p> </div> {% else %} <div class="content"> <div class="layui-inline img"><img src="{{ intro.image.url }}"></div><div class="layui-inline panel"> <p>{{ intro.content }}</p> </div> </div> {% endif %} {% endfor %}TIP
在模版中遍历时可以用{% if forloop.counter|divisibleby:2 %}来判断当前是否是偶数成长历程的遍历同理#配置错误页面
#准备相关的错误页面
404.html#修改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<path>.*)$, serve, {"document_root": STATIC_ROOT}), ]#收集项目所需依赖文件
pip3 freeze > requirements.txt#部署上线
#购买云服务器(以阿里云为例)
购买时操作系统选择CentOS 7.7 64位记录远程连接密码,在远程连接时用重置实例密码,该密码是登陆系统时使用#开放云服务器的端口
在云服务器对应的实例中安全组规则中添加
允许 自定义 TCP 80/80 IPv4地址段访问 0.0.0.0/0 允许 自定义 TCP 8000/8000 IPv4地址段访问 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/local make make install #这一步比较耗时 4.更改/usr/bin/python链接ln -s /usr/local/bin/python3.7 /usr/bin/python3 ln -s /usr/local/bin/pip3.7 /usr/bin/pip3#安装新版sqlite
1.下载源码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/ 2.把sqlite安装到 /usr/local 目录./configure --prefix=/usr/local make make 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/python3 yum install python-setuptools python-devel pip3 install virtualenvwrapper 2.修改~/.bashrc文件export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3 export WORKON_HOME=$HOME/.virtualenvs source /usr/local/bin/virtualenvwrapper.sh 3.从新加载~/.bashrc文件source ~/.bashrcTIP
如果出现找不到文件,可以使用以下命令查找文件的位置
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.测试在项目的根目录运行
#项目名称.wsgi uwsgi --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 # 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 4.启动uwsgiworkon pycms # -d表示后台运行 uwsgi -d -i 项目根目录/config/uwsgi.ini 5.查看启动ps aux|grep uwsgiTIP
注意:用配置文件启动的uwsgi不能直接在浏览器中访问
6.查看端口netstat -lpnt 6.关闭uwsgikillall -9 uwsgi#安装nginx
nginx主要用来反向代理,端口转发
1.安装sudo yum install epel-release sudo yum install nginx 2.启动sudo systemctl start nginx 3.新建 项目根目录/config/nginx.conf# 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 } } 4.将该配置文件加入到nginx的启动配置文件中sudo ln -s pycms_nginx.conf /etc/nginx/conf.d/ 修改 /etc/nginx/nginx.confuser root 6.启动nginxsudo systemctl start nginx 7.重启nigxsudo systemctl restart nginx#附录:pycharm常用调试技巧
在需要调试的代码对应的行号处单击设置断点右键以debug模式运行代码,代码会暂停在端点处,常见调试按钮F8(第二个按钮) 执行下一步F7(第三个按钮) 进入函数内部Shift+F8(第六个按钮) 跳出函数option + F9(最后一个按钮) 直接跳转到下一个断点处