文章目录
项目源代码的下载地址 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>