项目源代码的下载地址 code aliyun
项目代码下载学习地址
https://code.aliyun.com/734449600/shequguanli/repository/archive.zip?ref=master
编辑好的容器使用
容器大小 252mb
纯净容器地址:registry.cn-hangzhou.aliyuncs.com/mkmk/django:uwsgi
软件bug修复版 registry.cn-hangzhou.aliyuncs.com/mkmk/django:uwsgixctcmanagev1
使用说明
docker run -tid --name uwsgidjango -p 40022:22 -p 48000:8000 --privileged=true registry.cn-hangzhou.aliyuncs.com/mkmk/django:uwsgixctcmanagev1 init
生产环境使用可以关闭掉 22 端口, 不写 40022:22 就是关闭容器端口
现在容器中已经有了一个/home/django10 项目 作为展示
将你的django 项目 替换 /home/django10
保留django10 中的 django10.xml 文件
修改为你的项目名称即可
docker exec -it uwsgidjango /bin/bash 执行启动脚本 startDjangoUwsgiNginx.sh
一条命令启动容器
当你完全配置好你的项目以后,可以将你的项目提交为镜像
并使用如下命令直接启动
docker run -tid --name uwsgidjango -p 40022:22 -p 48000:8000 --privileged=true registry.cn-hangzhou.aliyuncs.com/mkmk/django:uwsgixctcmanagev1 init && docker exec -d uwsgidjango /bin/bash -c "/usr/bin/startDjangoUwsgiNginx.sh"
部署到服务器docker截图
本地docker截图
创建环境容器
docker pull registry.cn-hangzhou.aliyuncs.com/mkmk/centos:ssh docker run -tid --name uwsgidjango -p 40022:22 -p 48000:8000 --privileged=true registry.cn-hangzhou.aliyuncs.com/mkmk/centos:ssh init
检查编码与时间是否正常
locale LANG=zh_CN.UTF-8 LC_CTYPE="zh_CN.UTF-8" LC_NUMERIC="zh_CN.UTF-8" LC_TIME="zh_CN.UTF-8" LC_COLLATE="zh_CN.UTF-8" LC_MONETARY="zh_CN.UTF-8" LC_MESSAGES="zh_CN.UTF-8" LC_PAPER="zh_CN.UTF-8" LC_NAME="zh_CN.UTF-8" LC_ADDRESS="zh_CN.UTF-8" LC_TELEPHONE="zh_CN.UTF-8" LC_MEASUREMENT="zh_CN.UTF-8" LC_IDENTIFICATION="zh_CN.UTF-8" LC_ALL=zh_CN.UTF-8
date 2020年 03月 29日 星期日 11:26:52 CST
配置必要的环境
python3
yum install python3
安装uwsgi
# 安装依赖 yum install gcc python36-devel kernel-devel libxml* pip3 install uwsgi
ln -s /usr/local/bin/uwsgi /usr/bin/uwsgi uwsgi -version *** Starting uWSGI 2.0.18 (64bit) on [Sun Mar 29 11:45:14 2020]
配置uwsgi
在项目路径下 django10 等于项目名称
touch /home/django10/django10.xml chmod 777 /home/django10/django10.xml
添加如下内容
<uwsgi> <socket>127.0.0.1:8999</socket> <!-- 内部端口,自定义 --> <chdir>/home/django10/</chdir> <!-- 项目路径 --> <module>django10.wsgi</module> <!-- Logistics为wsgi.py所在目录名--> <processes>4</processes> <!-- 进程数 --> <http-keepalive>true</http-keepalive> <buffer-size> 32768 </buffer-size> <daemonize>/home/django10/uwsgi.log</daemonize> <!-- 日志文件 --> </uwsgi>
nginx
安装nginx
#安装拓展包,否则找不到nginx yum install epel-release yum install nginx
升级sqllite3
由于django需要sqllite3 大于3.8
但是centos自带的sqllite == 3.7 ,所以需要升级
# 下载源码 wget https://www.sqlite.org/2019/sqlite-autoconf-3290000.tar.gz # 编译 tar zxvf sqlite-autoconf-3290000.tar.gz cd sqlite-autoconf-3290000/ ./configure --prefix=/usr/local make && make install # 替换系统低版本 sqlite3 mv /usr/bin/sqlite3 /usr/bin/sqlite3_old ln -s /usr/local/bin/sqlite3 /usr/bin/sqlite3 echo "/usr/local/lib" > /etc/ld.so.conf.d/sqlite3.conf ldconfig sqlite3 -version 3.29.0 2019-07-10 17:32:03 fc82b73eaac8b36950
配置nginx
# For more information on configuration, see: # * Official English Documentation: http://nginx.org/en/docs/ # * Official Russian Documentation: http://nginx.org/ru/docs/ user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; # Load dynamic modules. See /usr/share/doc/nginx/README.dynamic. include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; # Load modular configuration files from the /etc/nginx/conf.d directory. # See http://nginx.org/en/docs/ngx_core_module.html#include # for more information. include /etc/nginx/conf.d/*.conf; server { listen 80 default_server; listen [::]:80 default_server; server_name _; root /usr/share/nginx/html; # Load configuration files for the default server block. include /etc/nginx/default.d/*.conf; location / { } error_page 404 /404.html; location = /40x.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } } server { listen 8000; server_name _ ; large_client_header_buffers 4 32k; client_header_buffer_size 1k; charset utf-8; root /home/django10; #项目路径 location / { include uwsgi_params; uwsgi_pass 127.0.0.1:8999; uwsgi_param UWSGI_SCRIPT django10.wsgi; uwsgi_param UWSGI_CHDIR /home/django10/;#项目路径 } location /static/ { alias /home/django10/static/; #静态资源路径 } } # Settings for a TLS enabled server. # # server { # listen 443 ssl http2 default_server; # listen [::]:443 ssl http2 default_server; # server_name _; # root /usr/share/nginx/html; # # ssl_certificate "/etc/pki/nginx/server.crt"; # ssl_certificate_key "/etc/pki/nginx/private/server.key"; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 10m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # # # Load configuration files for the default server block. # include /etc/nginx/default.d/*.conf; # # location / { # } # # error_page 404 /404.html; # location = /40x.html { # } # # error_page 500 502 503 504 /50x.html; # location = /50x.html { # } # } }
启动服务
编写启动脚本
## 编写启动脚本 touch /home/startDjangoUwsgiNginx.sh chmod 777 /home/startDjangoUwsgiNginx.sh ln -s /home/startDjangoUwsgiNginx.sh /usr/bin/startDjangoUwsgiNginx.sh
启动服务
startDjangoUwsgiNginx.sh 查看django.xml 中的日志文件的路径 ModuleNotFoundError: No module named 'django'
新建django 项目
#启动服务器
python manage.py runserver
#迁移应用的 数据库
python manage.py makemigrations polls
提交构建好的镜像
清除内部缓存
暂停进程 pkill -9 uwsgi pkill -9 python pkill -9 python3 pkill -9 python* pkill -9 java #清除yum缓存 yum clean all rm -rf /var/cache/yum/* */ #清除pip 安装缓存 cd ~/.cache/pip rm -rf * echo 1 > /proc/sys/vm/drop_caches echo 2 > /proc/sys/vm/drop_caches echo 3 > /proc/sys/vm/drop_caches
docker commit [容器名称] registry.cn-hangzhou.aliyuncs.com/mkmk/django:uwsgi docker push registry.cn-hangzhou.aliyuncs.com/mkmk/django:uwsgi
vue-jquery-bootstrap-django-sqlite3项目开发
创建django项目
ps 觉得手动创建配置文件麻烦的,可以直接去我的 github 下载,示例代码,进行二次开发
创建django项目 项目目录如下
首先我们需要配置环境
导入vue jquery bootstrap
下载 vue.js jquery.js bootstrap.css 放到static 下
配置django静态资源路径
在 项目名/django10/setting.py 中 添加如下配置
STATIC_URL = '/static/' STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)
导入已有信息数据库
编写django setting.py 配置文件如下
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', # 修改这一行为你的数据库 # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 'NAME': os.path.join(BASE_DIR, 'xctrenyuanxinx.db'), } }
生成数据库 类
注意区分 django 项目名称 与应用名称
python3 manage.py inspectdb > 【app应用名称】/models.py
自动生成数据库如下:
编写view。py
相当于 servlet ,就是处理请求的方法
编写应用内 url.py 的路径映射
vi 项目名/应用名/url.py
from django.urls import path import villagemanage.views as views urlpatterns = [ path('index/', views.index, name='index'), path('index2/', views.index2, name='index2'), path('getgroupinfo/<pindex>/', views.getgroupinfo, name='getgroupinfo'), ]
添加应用内 url.py 的路径映射 到 项目中
vi 项目名/url.py
urlpatterns = [ path('admin/', admin.site.urls), path('', views.index, name='index'), path('vg/', include('villagemanage.urls')), ]
编写前端视图
里边应用了 vue,循环视图,ajax,jquery, 动态添加元素, 分页等技术,可以参考学习
将 index.html 放到 templates 目录下边
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link href="/static/css/bootstrap.min.css" rel="stylesheet"> <script src="/static/js/jquery-3.4.1.min.js"></script> <script src="/static/js/vue.min.js"></script> <script src="/static/js/bootstrap.min.js"></script> </head> <body style="overflow-y:Scroll;overflow-x:hidden"> <div id="vue1" > {# 菜单列#} <div class="row navbar bg-dark navbar-dark "> <button class="navbar-toggler bg-secondary navbar-dark" type="button" data-toggle="collapse" data-target="#collapsibleNavbar"> <a class="navbar-brand" href="#">菜单</a> <span class="navbar-toggler-icon"></span> </button> <div class="col-10 d-flex flex-row-reverse " > <nav class="navbar navbar-expand-sm bg-secondary navbar-dark"> <ul class="navbar-nav "> <li class="nav-item"> <a class="nav-link text-white" href="#">关于</a> </li> <li class="nav-item"> <a class="nav-link text-white" href="#">帮助</a> </li> <li class="nav-item"> <a class="nav-link text-white" href="#">登录</a> </li> </ul> </nav> </div> </div> {# 标题导航一下的内容#} <div class="d-flex"> {# 可以展开可以隐藏的 #} <div id="collapsibleNavbar" class=" collapse bg-light text-dark"> <div id="accordion"> <div v-for="(item, index) in selectinner" :key="index"> <div class="card bg-light text-dark"> <div class="card-header" @click="gotosonpage(index)"> <a class="card-link" data-toggle="collapse" :href="getidbyindex('#info',index)" > [[ item.head ]] </a> </div> <div :id="getidbyindex('info',index)" class="collapse " data-parent="#accordion"> <div class="card-body"> [[ item.info ]] </div> </div> </div> </div> </div> </div> {# 实际内容展示#} <div class="flex-grow-1 bg-light text-dark"> <div id="sonpage1" v-if=" 0 == nowsonpage" class="col" style="display: flex; justify-content: center; align-items: center; flex-direction: column; width: 1550px"> <div class="row"> <form id="form1" class="form-inline" style="width: 1200px"> <div v-for="(item,index) in mulform.inputid " :key="index" > <label >[[mulform.inputname[index] ]]</label> <input type="text" class="form-control" :name="[[mulform.inputid[index] ]]" :placeholder="[[mulform.phd[index] ]]"> </div> <button type="button" @click="consologroupinfo()" class="btn btn-primary btn-lg">查询</button> </form> </div> <div class="border border-primary bg-light text-dark w-75 " style=" overflow:scroll;height: 600px"> <table class="table table-striped table-bordered" style="max-width: 90%"> {# 表头内容#} <thead class="thead-light" style="max-width: 90%"> <tr style="max-width: 90%"> <th style="white-space:nowrap ;max-width: 90%" v-for="item in mulform.tablehead ">[[item]]</th> </tr> </thead> {# 表格中的每条信息#} <tbody id="tb1" style="max-width: 90%"> </tbody> </table> </div> <div class="row"> <ol class="breadcrumb"> <li class="breadcrumb-item">共 <span class="badge badge-pill badge-success">[[sumpageindex]] </span> 页</li> <li class="breadcrumb-item"><span @click="gotothesepage(-1)" class="badge badge-pill badge-success">上一页 </span></li> <li class="breadcrumb-item">当前 <span class="badge badge-pill badge-success"> [[groupinfopindex]] 页</span></li> <li class="breadcrumb-item active"><span @click="gotothesepage(1)" class="badge badge-pill badge-success"> 下一页 </span></li> <li class="breadcrumb-item active">跳转至<input v-model="groupinfopindex" type="number" /> </li> <li class="breadcrumb-item active"><span class="badge badge-pill badge-primary" @click="consologroupinfo()"><h6>点击跳转</h6></span></li> </ol> </div> </div> <div id="sonpage2" v-if=" 1 == nowsonpage"> 模块 2 </div> <div id="sonpage3" v-if=" 2 == nowsonpage"> 模块 3 </div> </div> </div> </div> </body> <script type="text/javascript"> var vm = new Vue({ delimiters:['[[', ']]'], el: '#vue1', data: { {#代表当前显示的子页面序号#} nowsonpage:0, {# 下拉菜单中的标题以及介绍 #} selectinner:[{ "head": "按条件查询群体信息","info":"按照条件筛选出符合要求的多个人员信息" }, { "head": "个人信息录入与删除","info": "单个人员的信息导入与删除" }, { "head": "批量导入与删除","info": "批量导入多个人员信息,或者批量删除信息" }], {# 集体查询的提交表单 #} mulform:{inputid:["name","idnumber","loudao","danyuan","menpaihao","loudaozhang","nianling0","nianling1","xingbie"], inputname:["名字","身份证号码","楼道","单元 ","门牌号","楼道长","年龄下限","年龄上限","性别"], phd:["名字","身份证号码","楼道","单元 ","门牌号","楼道长","年龄下限","年龄上限","性别"], tablehead:["序号","姓名","年龄","性别","身份证号","管理类型","与户主关系","户主","户编号","楼栋","楼道长","楼道长电话","单元号","门牌号","本人联系电话","政治面貌","最高学历","民族","居住社区","婚姻状况"] }, groupinfo:new Array(), groupinfopindex:1, sumpageindex:"?" }, watch:{ groupinfo:{ //监听的对象 deep:true, //深度监听设置为 true handler:function(newV,oldV){ console.log('watch中:',newV) } } }, methods: { {# 将子页面切换到 index 子页面 #} gotosonpage: function(index){ this.nowsonpage=index }, {# 根据元素 id 以及 名称 绑定 id#} getidbyindex: function(name,index){ return name+"_"+index }, consologroupinfo:function (){ let that=this; $.ajax({ url : "/vg/getgroupinfo/"+that.groupinfopindex+"/", type : "post", headers : { "X-CSRFToken": '{{ csrf_token }}' }, dataType : "json", data : $("#form1").serialize(), success : function (data){ that.groupinfo=data.allinfo; that.sumpageindex=data.sumpageindex; var insertstr1="" for(let index1 in that.groupinfo){ {#console.log(item);#} insertstr1+='<tr style="max-width: 90%">' for(let index2 in that.groupinfo[index1]){ insertstr1+='<td style="max-width: 90%">'+that.groupinfo[index1][index2]+"</td>" } insertstr1+="</tr>" } var obj1=$("#tb1") obj1.empty(); obj1.append(insertstr1) console.log(that.groupinfo); {#alert(data.allinfo)#} }, error:function(){ alert("发生错误,请检查输入条件以及页最大编号"); } }); }, gotothesepage: function(offset){ this.groupinfopindex+=offset; if(this.groupinfopindex < 1){ this.groupinfopindex=1; alert("当前已经在第一页!") return; } if(this.groupinfopindex > this.sumpageindex){ this.groupinfopindex=this.sumpageindex; alert("当前已经在最后一页了!") return; } this.consologroupinfo(); }, details: function() { return this.site + " - 学的不仅是技术,更是梦想!"; } } }) </script> </html>
js常用代码
替换节点样式
思路,通常后端生成的元素节点样式难以改变,我们可以通过,隐藏节点,新建 好看的节点,关联两者的 各种事件即可
<script type="text/javascript"> {#$('#id_touxiang').value="上传",#} {# 美化上传文件的按钮 ,并优化 上传图片的大小 #} $(document).ready(function() { $('#id_touxiang').hide(); var button1 = $('<button type="button" class="btn btn-success" id="id_touxiang2" style="font-size: 60px">点击拍照或上传头像</button>'); $('#id_touxiang').after(button1); $('#id_touxiang2').click(function () { $('#id_touxiang').click() }); }); </script>
美化前后对比
选择文件时压缩图片
随着手机像素越来越高,上传图片时,图片体积太大时有发生,为了减轻服务器压力,压缩图片尺寸时必要的
//file 上传图片,绑定change事件 <input type="file" onChange="uploadPic(this)" accept="image/*" /> function uploadPic(e) { var file = e.files[0]; function callback(data){//回调获取压缩后的Blog if(data){ console.log("压缩成功") } } this.compress(file, callback); } //当图片宽度大于640时 进行等比例压缩,并返回Blob,否则返回false function compress(fileObj, callback) { function dataURLtoBlob(dataurl) {//base64格式图片 转为Blob var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); } if (typeof (FileReader) === 'undefined') { console.log("当前浏览器内核不支持base64图标压缩"); return false; } else { try { var reader = new FileReader(); var image = new Image(); reader.readAsDataURL(fileObj);//开始读取指定的Blob中的内容。返回base64 reader.onload = function (ev) { image.src = ev.target.result; image.onload = function () { var imgWidth = this.width, imgHeight = this.height; //获取图片宽高 if (imgWidth > 640) {//设置图片的最大宽度为640 imgWidth = 640; imgHeight = 640 / this.width * imgHeight;//设置等比例高度 var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); canvas.width = imgWidth; canvas.height = imgHeight; ctx.drawImage(this, 0, 0, imgWidth, imgHeight);//根据宽高绘制图片 var fullQuality = canvas.toDataURL("image/png", 1.0);//canvas转为base64 var blogData=dataURLtoBlob(fullQuality); callback(blogData); }else{ callback(false); } } } } catch (e) { console.log("压缩失败!"); } } }
图像压缩
依赖包网址https://cdn.jsdelivr.net/gh/WangYuLue/image-conversion/build/conversion.js function view(){ const file = document.getElementById(‘demo’).files[0]; console.log(file); imageConversion.compressAccurately(file,200).then(res=>{ //The res in the promise is a compressed Blob type (which can be treated as a File type) file; console.log(res); }) }
上传压缩的图片
第一步压缩图片到一个全局变量
function yasuoimg(elementid) { const file = document.getElementById(elementid).files[0]; {# console.log(file);#} imageConversion.compressAccurately(file,200).then(res=>{ //The res in the promise is a compressed Blob type (which can be treated as a File type) file; var inputfile0=document.getElementById(elementid).files[0]; console.log("压缩前",inputfile0); filehaveyasuo = new window.File([res],inputfile0.name,{ type: inputfile0.type }); console.log("压后",filehaveyasuo); $('#id_touxiang3').attr("src",URL.createObjectURL(res)); }) }
修改formdata 中的数据
<script type="text/javascript"> function uploadformset() { //得到django的 密匙 {#var csrftoken = getCookie('csrftoken');#} var form = new FormData(document.getElementById("uploadinfo2")); for (var key of form.keys()) { console.log("修改前",key); } console.log("压缩后的图片",filehaveyasuo); form.delete('touxiang') form.append('touxiang', filehaveyasuo) for (var key of form.keys()) { console.log("修改后",key); } console.log("修改添加的文件后",form.get('touxiang')) $.ajax({ cache: false, type: 'POST', // 根据表单id 生成数据 data: form, url: "/new/uploadoneinfo/", traditional:true, //为必须内容 //dataType:'json', //data为json时必须 processData: false, //为必须内容 contentType: false, //为必须内容 success: function(data) { console.log(data); }, beforeSend: function(xhr, settings) { {#xhr.setRequestHeader("X-CSRFToken", csrftoken);#} } }); } </script>