Docker-compose 八步部署Django + Uwsgi + Nginx + MySQL + Redis升级篇

Django在生产环境的部署还是比较复杂的, 令很多新手望而生畏, 幸运的是使用Docker容器化技术可以大大简化我们Django在生产环境的部署并提升我们应用的可移植性。Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux机器上。

 

前文我们介绍了如何使用docker-compose八步部署Django + Uwsgi + Nginx + MySQL + Redis (多容器组合),但该教程里有很多值得改进的地方,比如:

 

  • MySQL的数据库名,用户名和密码明文写在docker-compose.yml里,实际是可以由.env文件创建的;
  • MySQL使用的版本比较老,为5.7。如果你使用MySQL 8,那么相关配置文件需要做较大修改;
  • Nginx配置文件没有挂载,每次修改需要手动将配置文件从宿主机复制一份到容器内;
  • 容器间通信使用了–links选项,这个docker已不推荐使用。本例将使用networks实现容器间通信;
  • 原文每次web容器服务启动后,需要手动进入容器内部进行数据迁移并启动uwsgi服务;
  • 原文教程排错机制讲的较少,本文将仔细讲下如何在Docker部署时排错。

本文将是docker-compose部署Django + Uwsgi + Nginx + MySQL + Redis教程的升级版,将完善前面教程不足的地方,很多配置文件将会有非常大的参考价值,建议先收藏再阅读。

 

注意:本文侧重于Docker技术在部署Django时的实际应用,而不是Docker基础教程。对Docker命令不熟悉的读者们建议先学习下Docker及Docker-compose基础命令。

Docker-compose 八步部署Django + Uwsgi + Nginx + MySQL + Redis升级篇

什么是docker-compose及docker-compose工具的安装

Docker-compose是一个用来定义和运行复杂应用的 Docker 工具。使用 docker-compose 后不再需要使用 shell 脚本来逐一创建和启动容器,还可以通过 docker-compose.yml 文件构建和管理复杂多容器组合。

Docker-compose的下载和安装很简单,网上有很多教程,我就不再详述了。这里只记录下ubuntu系统下docker-compose的安装过程。

 # Step 1: 以ubuntu为例,下载docker-compose $ sudo curl -L https://github.com/docker/compose/releases/download/1.17.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose # Step 2: 给予docker-compose可执行权限 $ sudo chmod +x /usr/local/bin/docker-compose # Step 3: 查看docker-compose版本 $ docker-compose --version

注意:安装docker-compose前必需先安装好docker。

Django + Uwsgi + Nginx + MySQL + Redis组合容器示意图

本例中我们将使用docker-compose编排并启动4个容器,这更接近于实际生成环境下的部署。

  1. Django + Uwsgi容器:核心应用程序,处理动态请求

  2. MySQL 容器:数据库服务

  3. Redis 容器:缓存服务

  4. Nginx容器:反向代理服务并处理静态资源请求

这四个容器的依赖关系是:Django+Uwsgi 容器依赖 Redis 容器和 MySQL 容器,Nginx 容器依赖Django+Uwsgi容器。为了方便容器间的相互访问和通信,我们使用docker-compose时可以给每个容器取个别名,这样访问容器时就可以直接使用别名访问,而不使用Docker临时给容器分配的IP了。

这四个容器的别名及通信端口如下图所示:

Docker-compose 八步部署Django + Uwsgi + Nginx + MySQL + Redis升级篇

Docker-compose部署Django项目布局树形图

我们新建了一个compose文件夹,专门存放用于构建其它容器镜像的Dockerfile及配置文件。compose文件夹与django项目的根目录myproject同级。这样做的好处是不同的django项目可以共享compose文件夹。

myproject_docker # 项目根目录├── compose # 存放各项容器服务的Dockerfile和配置文件│   ├── mysql│   │   ├── conf│   │   │   └── my.cnf # MySQL配置文件│   │   └── init│   │       └── init.sql # MySQL启动脚本│   ├── nginx│   │   ├── Dockerfile # 构建Nginx镜像所的Dockerfile│   │   ├── log # 挂载保存nginx容器内日志log目录│   │   ├── nginx.conf # Nginx配置文件│   │   └── ssl # 如果需要配置https需要用到│   ├── redis│   │   └── redis.conf # redis配置文件│   └── uwsgi # 挂载保存django+uwsgi容器内uwsgi日志├── docker-compose.yml # 核心编排文件└── myproject # 常规Django项目目录    ├── Dockerfile # 构建Django+Uwsgi镜像的Dockerfile    ├── apps # 存放Django项目的各个apps    ├── manage.py    ├── myproject # Django项目配置文件    │   ├── asgi.py    │   ├── __init__.py    │   ├── settings.py    │   ├── urls.py    │   └── wsgi.py    ├── pip.conf # 非必需。pypi源设置成国内,加速pip安装    ├── requirements.txt # Django项目依赖文件    ├── .env # 环境变量文件    ├── start.sh # 启动Django+Uwsgi容器后要执行的脚本    ├── media # 用户上传的媒体资源,如果没有需手动创建    ├── static #搜集项目的静态文件夹,如果没有需手动创建    └── uwsgi.ini # uwsgi配置文件

下面我们开始正式部署。

第一步:编写docker-compose.yml文件

修改过的docker-compose.yml的核心内容如下。我们定义了4个数据卷,用于挂载各个容器内动态生成的数据,比如MySQL的存储数据,redis生成的快照、django+uwsgi容器中收集的静态文件以及用户上传的媒体资源。这样即使删除容器,容器内产生的数据也不会丢失。

我们还定义了3个网络,分别为nginx_network(用于nginx和web容器间的通信),db_network(用于db和web容器间的通信)和redis_network(用于redis和web容器间的通信)。

整个编排里包含4项容器服务,别名分别为redis, db, nginxweb,接下来我们将依次看看各个容器的Dockerfile和配置文件。

version: "3"
volumes: # 自定义数据卷  db_vol: #定义数据卷同步存放容器内mysql数据  redis_vol: #定义数据卷同步存放redis数据  media_vol: #定义数据卷同步存放web项目用户上传到media文件夹的数据  static_vol: #定义数据卷同步存放web项目static文件夹的数据
networks: # 自定义网络(默认桥接), 不使用links通信  nginx_network:    driver: bridge  db_network:    driver: bridge  redis_network:     driver: bridge
services:  redis:    image: redis:latest    command: redis-server /etc/redis/redis.conf # 容器启动后启动redis服务器    networks:      - redis_network    volumes:      - redis_vol:/data # 通过挂载给redis数据备份      - ./compose/redis/redis.conf:/etc/redis/redis.conf # 挂载redis配置文件    ports:      - "6379:6379"    restart: always # always表容器运行发生错误时一直重启
  db:    image: mysql    env_file:        - ./myproject/.env # 使用了环境变量文件    networks:        - db_network    volumes:      - db_vol:/var/lib/mysql:rw # 挂载数据库数据, 可读可写      - ./compose/mysql/conf/my.cnf:/etc/mysql/my.cnf # 挂载配置文件      - ./compose/mysql/init:/docker-entrypoint-initdb.d/ # 挂载数据初始化sql脚本    ports:      - "3306:3306" # 与配置文件保持一致    restart: always
  web:    build: ./myproject    expose:      - "8000"    volumes:      - ./myproject:/var/www/html/myproject # 挂载项目代码      - static_vol:/var/www/html/myproject/static # 以数据卷挂载容器内static文件      - media_vol:/var/www/html/myproject/media # 以数据卷挂载容器内用户上传媒体文件      - ./compose/uwsgi:/tmp # 挂载uwsgi日志    networks:      - nginx_network      - db_network        - redis_network     depends_on:      - db      - redis    restart: always    tty: true    stdin_open: true
  nginx:    build: ./compose/nginx    ports:      - "80:80"      - "443:443"    expose:      - "80"    volumes:      - ./compose/nginx/nginx.conf:/etc/nginx/conf.d/nginx.conf # 挂载nginx配置文件      - ./compose/nginx/ssl:/usr/share/nginx/ssl # 挂载ssl证书目录      - ./compose/nginx/log:/var/log/nginx # 挂载日志      - static_vol:/usr/share/nginx/html/static # 挂载静态文件      - media_vol:/usr/share/nginx/html/media # 挂载用户上传媒体文件    networks:      - nginx_network    depends_on:      - web    restart: always

第二步:编写Web (Django+Uwsgi)镜像和容器所需文件

构建Web镜像(Django+Uwsgi)的所使用的Dockerfile如下所示:

# 建立 python 3.9环境FROM python:3.9
# 安装netcatRUN apt-get update && apt install -y netcat
# 镜像作者大江狗MAINTAINER DJG
# 设置 python 环境变量ENV PYTHONDONTWRITEBYTECODE 1ENV PYTHONUNBUFFERED 1
# 可选:设置镜像源为国内COPY pip.conf /root/.pip/pip.conf
# 容器内创建 myproject 文件夹ENV APP_HOME=/var/www/html/myprojectRUN mkdir -p $APP_HOMEWORKDIR $APP_HOME
# 将当前目录加入到工作目录中(. 表示当前目录)ADD . $APP_HOME
# 更新pip版本RUN /usr/local/bin/python -m pip install --upgrade pip
# 安装项目依赖RUN pip install -r requirements/production.txt
# 移除r in windowsRUN sed -i 's/r//' ./start.sh
# 给start.sh可执行权限RUN chmod +x ./start.sh
# 数据迁移,并使用uwsgi启动服务ENTRYPOINT /bin/bash ./start.sh

本Django项目所依赖的requirements.txt内容如下所示:

# djangodjango==3.2# uwsgiuwsgi==2.0.18# mysqlmysqlclient==1.4.6# redisdjango-redis==4.12.1redis==3.5.3# for imagesPillow==8.2.0 

start.sh脚本文件内容如下所示。最重要的是最后一句,使用uwsgi.ini配置文件启动Django服务。

#!/bin/bash# 从第一行到最后一行分别表示:# 1. 等待MySQL服务启动后再进行数据迁移。nc即netcat缩写# 2. 收集静态文件到根目录static文件夹,# 3. 生成数据库可执行文件,# 4. 根据数据库可执行文件来修改数据库# 5. 用 uwsgi启动 django 服务# 6. tail空命令防止web容器执行脚本后退出while ! nc -z db 3306 ; do    echo "Waiting for the MySQL Server"    sleep 3done
python manage.py collectstatic --noinput&&python manage.py makemigrations&&python manage.py migrate&&uwsgi --ini /var/www/html/myproject/uwsgi.ini&&tail -f /dev/null
exec "$@"

uwsgi.ini配置文件如下所示: 

[uwsgi]
project=myprojectuid=www-datagid=www-database=/var/www/html
chdir=%(base)/%(project)module=%(project).wsgi:applicationmaster=Trueprocesses=2
socket=0.0.0.0:8000chown-socket=%(uid):www-datachmod-socket=664
vacuum=Truemax-requests=5000
pidfile=/tmp/%(project)-master.piddaemonize=/tmp/%(project)-uwsgi.log
#设置一个请求的超时时间(秒),如果一个请求超过了这个时间,则请求被丢弃harakiri = 60post buffering = 8192buffer-size= 65535#当一个请求被harakiri杀掉会,会输出一条日志harakiri-verbose = true
#开启内存使用情况报告memory-report = true
#设置平滑的重启(直到处理完接收到的请求)的长等待时间(秒)reload-mercy = 10
#设置工作进程使用虚拟内存超过N MB就回收重启reload-on-as= 1024

第三步:编写Nginx镜像和容器所需文件

构建Nginx镜像所使用的Dockerfile如下所示:

# nginx镜像compose/nginx/Dockerfile
FROM nginx:latest
# 删除原有配置文件,创建静态资源文件夹和ssl证书保存文件夹RUN rm /etc/nginx/conf.d/default.conf && mkdir -p /usr/share/nginx/html/static && mkdir -p /usr/share/nginx/html/media && mkdir -p /usr/share/nginx/ssl
# 设置Media文件夹用户和用户组为Linux默认www-data, 并给予可读和可执行权限,# 否则用户上传的图片无法正确显示。RUN chown -R www-data:www-data /usr/share/nginx/html/media && chmod -R 775 /usr/share/nginx/html/media
# 添加配置文件ADD ./nginx.conf /etc/nginx/conf.d/
# 关闭守护模式CMD ["nginx", "-g", "daemon off;"]

Nginx的配置文件如下所示

# nginx配置文件# compose/nginx/nginx.conf
upstream django {    ip_hash;    server web:8000; # Docker-compose web服务端口}
# 配置http请求,80端口server {    listen 80; # 监听80端口    server_name 127.0.0.1; # 可以是nginx容器所在ip地址或127.0.0.1,不能写宿主机外网ip地址
    charset utf-8;    client_max_body_size 10M; # 限制用户上传文件大小
    access_log /var/log/nginx/access.log main;    error_log /var/log/nginx/error.log warn;
    location /static {        alias /usr/share/nginx/html/static; # 静态资源路径    }
    location /media {        alias /usr/share/nginx/html/media; # 媒体资源,用户上传文件路径    }
    location / {        include /etc/nginx/uwsgi_params;        uwsgi_pass django;        uwsgi_read_timeout 600;        uwsgi_connect_timeout 600;        uwsgi_send_timeout 600;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        proxy_redirect off;        proxy_set_header X-Real-IP  $remote_addr;       # proxy_pass http://django;  # 使用uwsgi通信,而不是http,所以不使用proxy_pass。    }}

第四步:编写Db (MySQL)容器配置文件

启动MySQL容器我们直接使用官方镜像即可,不过我们需要给MySQL增加配置文件。

# compose/mysql/conf/my.cnf[mysqld]user=mysqldefault-storage-engine=INNODBcharacter-set-server=utf8secure-file-priv=NULL # mysql 8 新增这行配置default-authentication-plugin=mysql_native_password  # mysql 8 新增这行配置
port            = 3306 # 端口与docker-compose里映射端口保持一致#bind-address= localhost #一定要注释掉,mysql所在容器和django所在容器不同IP
basedir         = /usrdatadir         = /var/lib/mysqltmpdir          = /tmppid-file        = /var/run/mysqld/mysqld.pidsocket          = /var/run/mysqld/mysqld.sockskip-name-resolve  # 这个参数是禁止域名解析的,远程访问推荐开启skip_name_resolve。
[client]port = 3306default-character-set=utf8
[mysql]no-auto-rehashdefault-character-set=utf8

我们还需设置MySQL服务启动时需要执行的脚本命令, 注意这里的用户名和password必需和docker-compose.yml里与MySQL相关的环境变量(.env)保持一致。

# compose/mysql/init/init.sqlAlter user 'dbuser'@'%' IDENTIFIED WITH mysql_native_password BY 'password';GRANT ALL PRIVILEGES ON myproject.* TO 'dbuser'@'%';FLUSH PRIVILEGES;

.env文件内容如下所示:

MYSQL_ROOT_PASSWORD=123456MYSQL_USER=dbuserMYSQL_DATABASE=myprojectMYSQL_PASSWORD=password

第五步:编写Redis 容器配置文件

启动redis容器我们直接使用官方镜像即可,不过我们需要给redis增加配置文件。大部分情况下采用默认配置就好了,这里我们只做出了如下几条核心改动:

 # compose/redis/redis.conf # Redis 5配置文件下载地址 # https://raw.githubusercontent.com/antirez/redis/5.0/redis.conf
 # 请注释掉下面一行,变成#bind 127.0.0.1,这样其它机器或容器也可访问 bind 127.0.0.1
 # 取消下行注释,给redis设置登录密码。这个密码django settings.py会用到。 requirepass yourpassword

第六步:修改Django项目settings.py

在你准备好docker-compose.yml并编排好各容器的Dockerfile及配置文件后,请先不要急于使用Docker-compose命令构建镜像和启动容器。这时还有一件非常重要的事情要做,那就是修改Django的settings.py, 提供mysql和redis服务的配置信息。最重要的几项配置如下所示:

 # 生产环境设置 Debug = False Debug = False
 # 设置ALLOWED HOSTS ALLOWED_HOSTS = ['your_server_IP', 'your_domain_name']
 # 设置STATIC ROOT 和 STATIC URL STATIC_ROOT = os.path.join(BASE_DIR, 'static') STATIC_URL = "/static/"
 # 设置MEDIA ROOT 和 MEDIA URL MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_URL = "/media/"
 # 设置数据库。这里用户名和密码必需和docker-compose.yml里mysql环境变量保持一致 DATABASES = {     'default': {         'ENGINE': 'django.db.backends.mysql',         'NAME': 'myproject', # 数据库名         'USER':'dbuser', # 你设置的用户名 - 非root用户         'PASSWORD':'password', # # 换成你自己密码         'HOST': 'db', # 注意:这里使用的是db别名,docker会自动解析成ip         'PORT':'3306', # 端口     } }
 # 设置redis缓存。这里密码为redis.conf里设置的密码 CACHES = {     "default": {         "BACKEND": "django_redis.cache.RedisCache",         "LOCATION": "redis://redis:6379/1", #这里直接使用redis别名作为host ip地址         "OPTIONS": {             "CLIENT_CLASS": "django_redis.client.DefaultClient",             "PASSWORD": "yourpassword", # 换成你自己密码         },     } }

第七步:使用docker-compose 构建镜像并启动容器组服务

现在我们可以使用docker-compose命名构建镜像并启动容器组了。

 # 进入docker-compose.yml所在文件夹,输入以下命令构建镜像 sudo docker-compose build # 启动容器组服务 sudo docker-compose up

如果一切顺利,此时你应该可以看到四个容器都已经成功运行了。

Docker-compose 八步部署Django + Uwsgi + Nginx + MySQL + Redis升级篇此时打开你的浏览器,输入你服务器的ip地址或域名指向地址,你就应该可以看到网站已经上线啦。

第八步:排错

初学者使用Docker或Docker-compose部署会出现各种各样的错误,本文教你如何排错。

Nginx容器排错

容器已启动运行,网站打不开,最有用的是查看Nginx的错误日志error.log。由于我们对容器内Nginx的log进行了挂载,你在宿主机的/compose/nginx/log目录里即可查看相关日志。

 # 进入nginx日志目录,一个access.log, 一个error.log cd compose/nginx/log # 查看日志文件 sudo cat error.log

绝大部分网站打不开,Nginx日志显示nginx: connect() failed (111: Connection refused) while connecting to upstreamNginx 502 gateway的错误都不是因为nginx自身的原因,而是Web容器中Django程序有问题或则uwsgi配置文件有问题。

在进入Web容器排错前,你首先要检查下Nginx转发请求的方式(proxy_pass和uwsgi_pass)以及转发端口与uwsgi里面的监听方式以及端口是否一致。

uWSGI和Nginx之间有3种通信方式unix socket,TCP socket和http如果Nginx以proxy_pass方式转发请求,uwsgi需要使用http协议进行通信。如果Nginx以uwsgi_pass转发请求,uwsgi建议配置socket进行通信。

更多关于Nginx和Uwsgi的配置介绍见个人博客:

  • https://pythondjango.cn/python/tools/6-uwsgi-configuration/

  • https://pythondjango.cn/python/tools/5-nginx-configuration/

Web容器排错

Web容器也就是Django+UWSGI所在的容器,是最容易出现错误的容器。如果Nginx配置没问题,你应该进入web容器查看运行脚本命令时有没有报错,并检查uwsgi的运行日志。uwsgi的日志非常有用,它会记录Django程序运行时发生了哪些错误或异常。一旦发生了错误,uwsgi的进程虽然不会停止,但也无法正常工作,自然也就不能处理nginx转发的动态请求从而出现nginx报错了。 

 # 查看web容器日志 $ docker-compose logs web # 进入web容器执行启动命令,查看有无报错 $ docker-compose exec web /bin/bash start.sh # 或则进入web柔情其,逐一执行python manage.py命令 $ docker-compose exec web /bin/bash  # 进入web容器,查看uwsgi是否正常启动 $ ps aux | grep uwsgi  # 进入uwsgi日志所在目录,查看Django项目是否有报错 cd /tmp

另外一个常发生的错误是 docker-compose生成的web容器执行脚本命令后立刻退出(exited with code 0), 这时的解决方案是在docker-compose.yml中包含以下2行,  另外脚本命令里加入tail -f /dev/null是容器服务持续运行。

 stdin_open: true tty: true

有时web容器会出现不能连接到数据库的报错,这时需要检查settings.py中的数据库配置信息是否正确(比如host为db),并检查web容器和db容器是否通过db_network正常通信(比如进入db容器查看数据表是否已经生成)。在进行数据库迁移时web容器还会出现if table exists or failed to open the referenced table ‘users_user’,  inconsistent migration history的错误, 可以删除migrations目录下文件并进入MySQL容器删除django_migrations数据表即可。

数据库db容器排错

我们还需要经常进入数据库容器查看数据表是否已生成并删除一些数据,这时可以使用如下命令:

 $ docker-compose exec db /bin/bash # 登录 mysql -u usernmae -p; # 选择数据库 USE dbname; # 显示数据表 SHOW tables; # 清空数据表 DELETE from tablenames; # 删除数据表,特别是Django migrationstable DROP TABLE tablenames;

小结

本文详细地介绍了如何使用docker-compose工具分七步在生成环境下部署Django + Uwsgi + Nginx + MySQL + Redis。过程看似很复杂,但很多Dockerfile,项目布局及docker-compose.yml都是可以复用的。花时间学习并练习本章内容是非常值得的,一但你学会了,基本上可以10分钟内完成一个正式Django项目的部署,而且可以保证在任何一台Linux机器上顺利地运行。本文最后的排错文章更会助你一臂之力。

注意:整个部署过程如果遇到问题,可以给我们留言或发信息,可以节省你的时间。

相关阅读

Docker部署Django由浅入深系列(下): 八步部署Django+Uwsgi+Nginx+MySQL+Redis

如何在阿里云Ubuntu服务器通过uWSGI和Nginx部署Django项目教程-大江狗原创出品

转自:https://mp.weixin.qq.com/s?__biz=MjM5OTMyODA4Nw==&mid=2247486903&idx=1&sn=5d2172f66c0357ffaefac7c783c80867&chksm=a73c6d8f904be4999d7844a7f70f9d3aa8cc460cd18089f13924711a3261cd4c69d1c7b6933e&scene=132#wechat_redirect

Django实战: 手把手教你配置Django SimpleUI打造美丽后台(多图)

很多人对Django自带的管理后台admin是又爱又恨,优点是几行代码配置就可以撸出一个功能性强的管理后台,缺点就是不怎么美观,感觉拿不出手。在所有的Django后台美化插件中,SimpleUI处于第一阵营,非常符合国人的审美观。本文将手把手教你如何配置使用Simple UI, 包括自定义菜单和控制面板等高级使用技巧.

 

安装

第一步 pip安装并加入INSTALLED_APPS

 pip install django-simpleui

修改settings.py, 将simpleui加入到INSTALLED_APPS里去,放在第一行,也就是django自带admin的前面

 INSTALLED_APPS = [
       'simpleui', # 注意这里
       'django.contrib.admin',
       'django.contrib.auth',
       'django.contrib.contenttypes',
       'django.contrib.sessions',
       'django.contrib.messages',
       'django.contrib.staticfiles',
       ...     
 ]

第二步 测试是否安装成功

使用python manage.py runserver命令启动本地测试服务器, 访问/admin/, 如果你能看到如下页面说明安装成功。

Django实战: 手把手教你配置Django SimpleUI打造美丽后台(多图)

登录后你还将看到如下用户界面:

Django实战: 手把手教你配置Django SimpleUI打造美丽后台(多图)

注意:如果你在生成环境中使用SimpleUI,还需要使用python manage.py collectstatic命令收集静态文件,否则样式无法正常显示。

常用配置

设置语言, 去Logo和管理后台名字

当你看到以上界面时,首先你想改动的一定是语言,去掉SimpleUI的默认logo,并把Django administration改成比如某某管理后台的名字。

修改settings.py, 添加如下代码:

 # 更改默认语言为中文
 LANGUAGE_CODE = 'zh-hans'
 
 # 去掉默认Logo或换成自己Logo链接
 SIMPLEUI_LOGO = 'https://th.bing.com/th/id/R2411a2b340731d67dfa0d84503e915e3?rik=zmYce%2fLys72JVQ&pid=ImgRaw'

修改管理后台的名称和标题要稍微复杂些,因为你不能直接在settings.py里进行配置。在任何一个app的目录下新建一个admin.py, 添加如下代码即可修改(本例app名为tasks)。这个设置属于Django的设置,不属于SimpleUI的设置。

 # tasks/admin.py
 from django.contrib import admin
 
 admin.site.site_header = '大江狗管理后台'  # 设置header
 admin.site.site_title = '大江狗管理后台'   # 设置title
 admin.site.index_title = '大江狗管理后台'
 
 from .models import Task
 admin.site.register(Task)

登录后的效果如下所示:

Django实战: 手把手教你配置Django SimpleUI打造美丽后台(多图)

现在你可以看到语言、logo和管理后台名字都已经改过来了。但是你会发现两个问题,左侧菜单的tasks显示的依然是英文,我们需要将其设置成中文。另外,右侧有simpleui的广告链接,页面背后有js文件跟踪simpleui的使用,这些都需要关闭。我们接下来教你如何解决这两个问题。

自定义或第三方APP名和模型名修改成中文

修改tasks/app.py, 通过verbose_name可以将app名改为中文,这里将tasks 改成了任务管理

 from django.apps import AppConfig
 
 class TasksConfig(AppConfig):
     name = 'tasks'
 
     verbose_name = '任务管理'

接着修改tasks/models.py, 以中文设置模型的verbose_name, 如下所示:

 from django.db import models
 
 class Status(models.TextChoices):
     UNSTARTED = 'u', "Not started yet"
     ONGOING = 'o', "Ongoing"
     FINISHED = 'f', "Finished"
 
 
 class Task(models.Model):
     name = models.CharField(verbose_name="Task name", max_length=65, unique=True)
     status = models.CharField(verbose_name="Task status", max_length=1, choices=Status.choices)
     
     class Meta:
         verbose_name = "任务"
         verbose_name_plural = "任务"
 
     def __str__(self):
         return self.name

现在刷新页面,你将看到tasks英文都变成中文了。

Django实战: 手把手教你配置Django SimpleUI打造美丽后台(多图)

实际Django开发中,我们还会用到第三方应用app和第三方app提供的模型,我们也可以通过打补丁的方式更改第三方app或模型以及模型字段的verbose_name或者label,将其修改成中文,如下所示:

 from third_package.models import ModelA
 
 ModelA._meta.verbose_name = ''
 ModelA._meta.verbose_name_plural = ''
 ModelA._meta.get_field('first_name').verbose_name = '名字'

关闭右侧广告链接和使用分析

修改settings.py, 添加如下两行代码:

 # 隐藏右侧SimpleUI广告链接和使用分析
 SIMPLEUI_HOME_INFO = False 
 SIMPLEUI_ANALYSIS = False 

现在查看效果,是不是清爽多了?

Django实战: 手把手教你配置Django SimpleUI打造美丽后台(多图)

实际上首页的快捷操作和最近动作也可以关闭,在自定义首页部分我们会讲到。

设置默认主题

SimpleUI默认主题(default)是深蓝色的,它支持的主题有Element-ui, Admin LteLayui等多种风格。你可以通过右上角下拉菜单改变主题,也可以在settings.py中设置默认主题,如下所示:

 # 设置默认主题,指向主题css文件名。Admin Lte风格
 SIMPLEUI_DEFAULT_THEME = 'admin.lte.css'
 
 # 设置默认主题,指向主题css文件名。Element-ui风格
 SIMPLEUI_DEFAULT_THEME = 'element.css'
 
 # 设置默认主题,指向主题css文件名。layui风格
 SIMPLEUI_DEFAULT_THEME = 'layui.css'
 
 # 设置默认主题,指向主题css文件名。紫色风格
 SIMPLEUI_DEFAULT_THEME = 'purple.css'

自定义菜单

左侧可折叠菜单是Simple UI系统默认菜单,根据已注册的应用和模型自动生成,其中父级菜单是App名,子菜单一般是所属App的各个模型名。SimpleUI甚至会自动为你分配默认图标,比如本例的tasks的应用使用了font-awsome的fa fa-tasks。在大多数情况下,Simple UI系统默认菜单不能满足需求,这时你就需要自定义菜单了,比如添加新的选项或给菜单选项分配新的图标。

修改settings.py, 添加如下代码:

 SIMPLEUI_CONFIG = {
      # 是否使用系统默认菜单,自定义菜单时建议关闭。
     'system_keep': False,
     
      # 用于菜单排序和过滤, 不填此字段为默认排序和全部显示。空列表[] 为全部不显示.
     'menu_display': ['任务管理', '权限认证'],
     
     # 设置是否开启动态菜单, 默认为False. 如果开启, 则会在每次用户登陆时刷新展示菜单内容。
     # 一般建议关闭。
     'dynamic': False,
     'menus': [
         {
             'app': 'auth',
             'name': '权限认证',
             'icon': 'fas fa-user-shield',
             'models': [
                 {
                 'name': '用户列表',
                 'icon': 'fa fa-user',
                 'url': 'auth/user/'
                 },
                 {
                     'name': '用户组',
                     'icon': 'fa fa-th-list',
                     'url': 'auth/group/'
                 }
             ]
         },
 
         {
             'name': '任务管理',
             'icon': 'fa fa-th-list',
             'models': [
                 {
                 'name': '任务列表',
                 # 注意url按'/admin/应用名小写/模型名小写/'命名。 
                 'url': '/admin/tasks/task/',
                 'icon': 'fa fa-tasks'
                 },
             ]
         },
     ]
 }

自定义菜单效果如下所示。我们更改了SimpleUI默认分配的图标。你还可以随意增减菜单选项并对其进行排序:

Django实战: 手把手教你配置Django SimpleUI打造美丽后台(多图)

自定义首页

SimpleUI默认首页由快捷链接和最近动作组成,我们可以将其隐藏,并将其链接到其它url。

继续修改settings.py, 添加如下代码:

 # 隐藏首页的快捷操作和最近动作
 SIMPLEUI_HOME_QUICK = False 
 SIMPLEUI_HOME_ACTION = False
 
 # 修改左侧菜单首页设置
 SIMPLEUI_HOME_PAGE = 'https://www.baidu.com'  # 指向页面
 SIMPLEUI_HOME_TITLE = '百度欢迎你!' # 首页标题
 SIMPLEUI_HOME_ICON = 'fa fa-code' # 首页图标
 
 # 设置右上角Home图标跳转链接,会以另外一个窗口打开
 SIMPLEUI_INDEX = 'https://www.baidu.com'

展示效果将如下所示:

Django实战: 手把手教你配置Django SimpleUI打造美丽后台(多图)

实际应用中后台首页通常是控制面板,需要用图表形式展示各种关键数据,这时就需要重写首页了。这里主要有两种实现方法。第一种是重写simpleui自带的home.html, 另一种自己编写一个控制面板的页面,然后设置首页指向它, 个人倾向于第二种, 因为它完全不涉及改动simpleui的源码。

我们现在开始使用Django编写一个用于显示控制面板的页面,用于在首页显示注册用户数量及任务数量。URL路由及对应的视图函数如下所示:

 # tasks/urls.py
 urlpatterns = [
     path('tasks/dashboard/', views.dashboard, name='dashboard'),
 ]
 
 # tasks/views.py
 from django.contrib.auth.models import User
 from django.shortcuts import render
 from .models import Task
 
 def dashboard(request):
     user_count = User.objects.count()
     task_count = Task.objects.count()
 
     context = { 'user_count': user_count, 'task_count': task_count }
     return render(request, 'tasks/dashboard.html',context)

我们的模板也很简单,使用了boostrap4的admin lte风格的卡片展示用户总数和任务总数。

 <!DOCTYPE html>
 <html>
 <head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <title>控制面板</title>
   <!-- Tell the browser to be responsive to screen width -->
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <!-- Theme style -->
     <link rel="stylesheet" href="https://adminlte.io/themes/AdminLTE/bower_components/bootstrap/dist/css/bootstrap.min.css">
   <link rel="stylesheet" href="https://adminlte.io/themes/AdminLTE/dist/css/AdminLTE.min.css">
 
 </head>
 <body>
 <div class="wrapper">
  <!-- Main content -->
     <section class="content">
       <div class="container-fluid">
         <!-- Small boxes (Stat box) -->
         <div class="row">
           <div class="col-sm-3">
             <!-- small box -->
             <div class="small-box bg-info">
               <div class="inner">
                 <h3>{{ user_count }}</h3>
 
                 <p>用户总数</p>
               </div>
               <div class="icon">
                 <i class="ion ion-bag"></i>
               </div>
               <a href="#" class="small-box-footer">更多信息 <i class="fas fa-arrow-circle-right"></i></a>
             </div>
           </div>
           <!-- ./col -->
           <div class="col-sm-3">
             <!-- small box -->
             <div class="small-box bg-success">
               <div class="inner">
                 <h3>{{ task_count }}</h3>
                 <p>任务总数</p>
               </div>
               <div class="icon">
                 <i class="ion ion-stats-bars"></i>
               </div>
               <a href="#" class="small-box-footer">更多信息 <i class="fas fa-arrow-circle-right"></i></a>
             </div>
           </div>
           <!-- ./col -->
              <div class="col-sm-3">
             <!-- small box -->
             <div class="small-box bg-info">
               <div class="inner">
                 <h3>{{ user_count }}</h3>
 
                 <p>用户总数</p>
               </div>
               <div class="icon">
                 <i class="ion ion-bag"></i>
               </div>
               <a href="#" class="small-box-footer">更多信息 <i class="fas fa-arrow-circle-right"></i></a>
             </div>
           </div>
           <!-- ./col -->
           <div class="col-sm-3">
             <!-- small box -->
             <div class="small-box bg-success">
               <div class="inner">
                 <h3>{{ task_count }}</h3>
 
                 <p>任务总数</p>
               </div>
               <div class="icon">
                 <i class="ion ion-stats-bars"></i>
               </div>
               <a href="#" class="small-box-footer">更多信息 <i class="fas fa-arrow-circle-right"></i></a>
             </div>
           </div>
           <!-- ./col -->
         </div>
       </div>
     </section>
   </div>
 </body>

现在修改我们的settings.py, 将首页指向这个新创建的控制面板。

 # 修改首页设置, 指向新创建的控制面板
 SIMPLEUI_HOME_PAGE = '/tasks/dashboard/'
 SIMPLEUI_HOME_TITLE = '控制面板!' 
 SIMPLEUI_HOME_ICON = 'fa fa-eye'

刷新浏览器,你就会发现我们的首页已经修改了,是不是很酷?

Django实战: 手把手教你配置Django SimpleUI打造美丽后台(多图)

Django SimpleUI, 你学会了吗? 体验完了SimpleUI, 我会用三个词语来描述它, 国人口味, 果然很美, 确实简单! 老规矩, 看懂了听懂了的留言点赞啊!

大江狗

转自:https://mp.weixin.qq.com/s/_HKXaea1entAf9guNRsv4A

​为什么我建议你使用django-extensions

django-extensions给django开发者提供了许多便捷的扩展工具(extensions),在github上高达5000颗星。小编我今天就介绍它包含哪些奥利给的有用扩展以及它们的使用场景。

​为什么我建议你使用django-extensions

django-extensions的安装

使用pip安装:

$ pip install django-extensions

然后把其加入settings.pyINSTALLED_APPS:

INSTALLED_APPS = [    ...    'django_extensions',]

django-extensions提供了哪几种扩展?

django-extensions主要提供了三种扩展:命令扩展,字段扩展和模型扩展。我们接下来分别介绍。

 

命令扩展

shell_plus

每次进行Django项目调试时,你首先需要打开python shell,再重新import每个model。如果安装了django-extensions, 使用python manage.py shell_plus命令将打开一个加强版的django shell,这个shell_plus为你自动载入项目中所有的model,可以让你很方便的开始调试。

 

show_urls

一句话可以展示当前项目所有定义的urls。

clear_cache

一句话清除缓存,在测试和开发环境很有用。

export_emails

一句话导出所有用户的email地址。

 

pipchecker

检查pip requirements.txt文件中是否有过期的packages,类似于pip list -o,只用于已安装过的packages。

其它有用的命令扩展还包括:

  • admin_generator: 只要你提供app label,就会自动为你输出定义的Admin Class代码,默认输出在stdout
  • clean_pyc: 移除项目中所有的pyc文件
  • create_command: 为一个app生成自定义命令所需要的目录结构。
  • create_template_tags: 为一个app生成template tag所需要的目录结构。
  • compile_pyc: 为项目编译python字节码
  • describe_form: 生产一个model的form代码,你可以将它拷贝到你的文件
  • delete_squashed_migrations: 删除残留的squash migration文件
  • dumpscript:生产一个python 脚本,用来重新填充数据库
  • export_emails: 为你的用户生成email地址
  • graph_model: 创建基于model的GraphViz2文件.
  • mail_debug: 开启一个邮件服务器,它会打印邮件内容而不是把它发送出去
  • merge_model_instances: 合并重复的model instance
  • notes: 展示代码中所有的 TODO, FIXME, BUG, HACK, WARNING, NOTE, XXX 的地方
  • passwd: 轻松修改用户密码
  • print_settings: 展示所有的,或者指定的django settings
  • print_user_for_session: 通过session来找到user,并且打印
  • drop_test_database: 删除测试数据库
  • reset_db: 使用DROP DATABASE和CREATE DATABASE来重置数据库
  • runprofileserver: 开启一个激活了profile功能的开发服务器
  • runscript: 在django上下文中运行一个脚本
  • runserver_plus: 标准的runserver加上Werkzeug的debugger工具
  • set_fake_emails: 根据用户的数据,为所有用户设置一个虚构的email
  • show_template_tags: 展示当前项目可用的template tags和template filters
  • sqldiff: 展示model和数据库是否结构不一样,如果有不一样的地方就展示出来
  • sqlcreate: 根据你的settings.py定义,为你生成创建数据库的SQL代码
  • sqldsn: 根据settings.py定义的数据库配置,返回一个可以用于其它程序的数据库URI
  • sync_s3: 将MEDIA_ROOT的文件复制到S3
  • update_permissions: 重载权限
  • validate_templates: 确认template是否有语法错误

字段扩展

django-extensions提供的最有用的字段扩展莫过于AutoSlugField, RandomCharFieldShortUUIDField。

 

AutoSlugField

很多时候我们需要在url里根据模型某个或多个字段(比如标题,用户名)生成一个独一无二的slug,便于搜索引擎发现我们的内容。AutoSlugField可以很轻松帮我们完成这个任务,而且永不重复。比如两篇文章有同样的标题,它会在第2篇文章的slug结尾上加上一个数字。下次如果你用django开发自己的博客,试试这个字段吧,保证你满意。

 

使用这个字段时先从django-extensions导入,然后指定根据哪些字段生成slug即可。它的强大之处在于它还支持自定义的模型方法和双下划线__关联模型查询。

slug = AutoSlugField(populate_from=['title', 'get_description', 'author__username'])

RandomCharField

验证用户身份时我们经常需要生成一个随机字符串发给用户,有时还需生成随机的邀请码。RandomCharField可以轻松实现这个目的。你还可以指定字符串长度和格式。

>>> RandomCharField(length=8, unique=True)BVm9GEaE
>>> RandomCharField(length=4, include_alpha=False)7097
>>> RandomCharField(length=12, include_punctuation=True)k[ZS.TR,0LHO
>>> RandomCharField(length=12, lowercase=True, include_digits=False)pzolbemetmok

ShortUUIDField

一个由22个字符组成的字符串,比正常的uuid短了很多。尽管不保证唯一,但重复概率极低。

 

模型扩展

django-extensions提供的最有用的模型基类扩展莫过于ActivatorModel, TitleDescriptionModel, TimeStampedModel TitleSlugDescriptionModel。使用时把你的模型继承这几个基类即可。

 

ActivatorModel

作为基类提供了 statusactivate_date,和 deactivate_date 这3个字段。status是一个choice选项,默认是activated。每次当你激活或失活一条记录时,日期会自动更新。它还提供了一个自定义Manager方法,允许使用Model.objects.active()查询所有处于活跃状态的对象。

 

TitleDescriptionModel

作为基类提供了title  description两个字段。title最长255个字符。

 

TimeStampedModel

作为基类提供了created  modified两个字段。这两个字段都是自我管理,自动更新的。

 

TitleSlugDescriptionModel

作为基类提供了title , description slug三个字段,其中slug根据title自动生成,独一无二。

 

所有以上扩展你最喜欢哪个呢? 欢迎留言。

大江狗原创

2020.12.15

转自:https://mp.weixin.qq.com/s/s8fEO9lDJ584aAVb6irLFQ

读书:《精通Django 3 Web开发》

manage.py:命令行工具,内置多种方式与项目进行交互。

asgi.py:用于启动异步通信服务

settings.py:项目的配置文件

urls.py:项目的路由设置,设置网站的具体网址内容

wsgi.py:全称为Python Web Server Gateway Interface,即Python服务器网关接口

创建应用XXX , pythonmanage.py startapp XXX

migrations:用于生成数据迁移文件,通过数据迁移文件可自动在数据库里生成相应的数据表。

apps.py:当前App的配置信息

admin.py:用于设置当前App的后台管理功能。

models.py:定义数据库的映射类,每个类可以关联一张数据表

tests.py:自动化测试的模块

views.py:视图文件,处理功能的业务逻辑

启动项目 python manage.py runserver 8001

内置的应用功能

admin:内置的后台管理系统。

auth:内置的用户认证系统。

contenttypes:记录项目中所有model元数据(Django的ORM框架)。sessions:Session会话功能,用于标识当前访问网站的用户身份,记录相关用户信息。

messages:消息提示功能。

staticfiles:查找静态资源路径。

中间件(Middleware)是一个用来处理Django请求(Request)和响应(Response)的框架级别的钩子,它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。

配置属性MIDDLEWARE的数据格式为列表类型,每个中间件的设置顺序是固定的,如果随意变更中间件很容易导致程序异常

SecurityMiddleware:内置的安全机制,保护用户与网站的通信安全。

SessionMiddleware:会话Session功能。

LocaleMiddleware:国际化和本地化功能。

CommonMiddleware:处理请求信息,规范化请求内容。

CsrfViewMiddleware:开启CSRF防护功能。

AuthenticationMiddleware:开启内置的用户认证系统。

MessageMiddleware:开启内置的信息提示功能。

XFrameOptionsMiddleware:防止恶意程序单击劫持。

静态资源的配置分别由配置属性STATIC_URL、STATICFILES_DIRS和STATIC_ROOT完成

新增数据

get_or_create方法,若存在返回数据表已有的数据信息,否则数据新增

update_or_create方法,若存在,则进行更新操作,否则在数据表里新增数据

数据显示视图、数据操作视图和日期筛选视图。

数据显示视图

RedirectView用于实现HTTP重定向,默认情况下只定义GET请求的处理方法。TemplateView是视图类的基础视图,可将数据传递给HTML模板,默认情况下只定义GET请求的处理方法。ListView是在TemplateView的基础上将数据以列表显示,通常将某个数据表的数据以列表表示。DetailView是在TemplateView的基础上将数据详细显示,通常获取数据表的单条数据。

数据操作视图是对模型进行操作,如增、删、改

FormView视图类使用内置的表单功能,通过表单实现数据验证、响应输出等功能,用于显示表单数据。CreateView实现模型的数据新增功能,通过内置的表单功能实现数据新增。UpdateView实现模型的数据修改功能,通过内置的表单功能实现数据修改。DeleteView实现模型的数据删除功能,通过内置的表单功能实现数据删除。

日期筛选视图是根据模型里的某个日期字段进行数据筛选的,然后将符合结果的数据以一定的形式显示在网页上。

Django模板引擎的解析过程

使用CSRF防护功能,首先在配置文件settings.py中设置CSRF防护功能。

表单设有隐藏控件csrfmiddlewaretoken,隐藏控件是由模板语法{% csrf_token %}生成的

取消表单的CSRF防护,那么可以在模板文件上删除{% csrf_token %},并且在对应的视图函数中添加装饰器@csrf_exempt

取消整个网站的CSRF防护,那么可以在settings.py的MIDDLEWARE注释的CSRF中间件CsrfViewMiddleware

对某些请求设置CSRF防护,那么可以在模板文件上添加模板语法{%csrf_token %},然后在对应的视图函数中添加装饰器@csrf_protect实现

创建static文件夹 python manage.py collectstatic

如果将Django设为调试模式(DEBUG=True),那么项目运行时将读取项目的pstatic文件夹的静态资源。

如果将Django设为调试模式(DEBUG=True),那么项目运行时将读取项目的pstatic文件夹的静态资源。

Django数据导入导出神器django-import-export使用教程

顾名思义,django-import-export是一个用于处理导入和导出数据的库。它支持多种格式,包括xls、csv、json、yaml以及tablib支持的所有其他格式。它还可以轻松与Django管理后台集成,使用起来非常方便。

安装插件

使用PIP安装

pip install django-import-export

更新settings.py:

INSTALLED_APPS = (
    ...
    'import_export',
)

还有一个可选的配置,我通常这样添加:

IMPORT_EXPORT_USE_TRANSACTIONS = True

默认值为False。它确定库是否会在数据导入中使用数据库事务,以确保安全。

编写资源Resources

django-import-export库使用Resource的概念,它的类定义非常类似于Django处理模型表单和管理类的方式。

在文档中,作者建议将与资源相关的代码放在admin.py文件。但是,如果实现与Django admin没有关系,我通常更喜欢在app文件夹里创建一个名为resources.py。

models.py

from django.db import models
class Person(models.Model):    name = models.CharField(max_length=30)    email = models.EmailField(blank=True)    birth_date = models.DateField()    location = models.CharField(max_length=100, blank=True)

resources.py

from import_export import resourcesfrom .models import Person
class PersonResource(resources.ModelResource):    class Meta:        model = Person

这是最简单的定义。您可以将几个配置传递给元类,fieldsexclude

导出数据

导出数据到CSV

from .resources import PersonResource
person_resource = PersonResource()
dataset = person_resource.export()
dataset.csv
id,name,email,birth_date,location
1,John,john@doe.com,2016-08-11,Helsinki
2,Peter,peter@example.com,2016-08-11,Helsinki
3,Maria,maria@gmail.com,2016-08-11,Barcelona
4,Vitor,vitor@freitas.com,2016-08-11,Oulu
5,Erica,erica@gmail.com,2016-08-11,Oulu

导出数据到JSON

dataset.json
[
  {"id"1"name""John""email""john@doe.com""birth_date""2016-08-11""location""Helsinki"},
  {"id"2"name""Peter""email""peter@example.com""birth_date""2016-08-11""location""Helsinki"},
  {"id"3"name""Maria""email""maria@gmail.com""birth_date""2016-08-11""location""Barcelona"},
  {"id"4"name""Vitor""email""vitor@freitas.com""birth_date""2016-08-11""location""Oulu"},
  {"id"5"name""Erica""email""erica@gmail.com""birth_date""2016-08-11""location""Oulu"}
]

导出数据到YAML

dataset.yaml
- {birth_date'2016-08-11', email: john@doe.com, id: 1, location: Helsinki, name: John}
- {birth_date'2016-08-11', email: peter@example.com, id: 2, location: Helsinki, name: Peter}
- {birth_date'2016-08-11', email: maria@gmail.com, id: 3, location: Barcelona, name: Maria}
- {birth_date'2016-08-11', email: vitor@freitas.com, id: 4, location: Oulu, name: Vitor}
- {birth_date'2016-08-11', email: erica@gmail.com, id: 5, location: Oulu, name: Erica}

过滤数据

from .resources import PersonResource
from .models import Person
person_resource = PersonResource()
queryset = Person.objects.filter(location='Helsinki')
dataset = person_resource.export(queryset)
dataset.yaml
- {birth_date'2016-08-11', email: john@doe.com, id: 1, location: Helsinki, name: John}
- {birth_date'2016-08-11', email: peter@example.com, id: 2, location: Helsinki, name: Peter}

导出到CSV视图

from django.http import HttpResponsefrom .resources import PersonResource
def export(request):    person_resource = PersonResource()    dataset = person_resource.export()    response = HttpResponse(dataset.csv, content_type='text/csv')    response['Content-Disposition'] = 'attachment; filename="persons.csv"'    return response

导出到Excel视图

from django.http import HttpResponsefrom .resources import PersonResource
def export(request):    person_resource = PersonResource()    dataset = person_resource.export()    response = HttpResponse(dataset.xls, content_type='application/vnd.ms-excel')    response['Content-Disposition'] = 'attachment; filename="persons.xls"'    return response

导入数据

查看new_persons.csv的数据

name,email,birth_date,location,id
Jessica,jessica@jones.com,2016-08-11,New York,
Mikko,mikko@suomi.com,2016-08-11,Jyväskyla,

id必须存在,因为它是主键。但是它会生成,所以我们不需要指定值。

import.html

{% extends 'base.html' %}
{% block content %}
  <form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <input type="file" name="myfile">
    <button type="submit">Upload</button>
  </form>
{% endblock %}

views.py

from tablib import Datasetdef simple_upload(request):    if request.method == 'POST':        person_resource = PersonResource()        dataset = Dataset()        new_persons = request.FILES['myfile']        imported_data = dataset.load(new_persons.read())        result = person_resource.import_data(dataset, dry_run=True)  # Test the data impor        if not result.has_errors():            person_resource.import_data(dataset, dry_run=False)  # Actually import now     return render(request, 'core/simple_upload.html')

Django后台管理集成

在admin.py里使用ImportExportModelAdmin,而不是ModelAdmin

from import_export.admin import ImportExportModelAdmin
from django.contrib import admin

from .models import Person

@admin.register(Person)
class PersonAdmin(ImportExportModelAdmin):
   pass

添加之后刷新页面你就会看到导入和导出按钮。

Django数据导入导出神器django-import-export使用教程

在导入现有项目时,导入功能具有良好的差异性:

Django数据导入导出神器django-import-export使用教程

这是一个强大的Django库,你可以用它做更多的事情。比如只想有导出功能,可以使用ExportMixin。

from .models import Personfrom django.contrib import adminfrom import_export.admin import ExportMixin
class PersonAdmin(ExportMixin, admin.ModelAdmin):    resource_class = PersonResource
admin.site.register(Person, BookAdmin)

详细文档地址:https://django-import-export.readthedocs.io/en/latest/

文章来源:Django中文网 作者:夜之舞。