惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
CXSECURITY Database RSS Feed - CXSecurity.com
K
Kaspersky official blog
A
Arctic Wolf
Attack and Defense Labs
Attack and Defense Labs
L
LINUX DO - 热门话题
N
News | PayPal Newsroom
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
L
Lohrmann on Cybersecurity
PCI Perspectives
PCI Perspectives
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
The Last Watchdog
The Last Watchdog
B
Blog RSS Feed
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
W
WeLiveSecurity
Know Your Adversary
Know Your Adversary
博客园 - Franky
T
Tenable Blog
T
Tailwind CSS Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Help Net Security
Help Net Security
WordPress大学
WordPress大学
T
The Exploit Database - CXSecurity.com
www.infosecurity-magazine.com
www.infosecurity-magazine.com
博客园 - 司徒正美
阮一峰的网络日志
阮一峰的网络日志
D
Darknet – Hacking Tools, Hacker News & Cyber Security
H
Heimdal Security Blog
TaoSecurity Blog
TaoSecurity Blog
S
Security Affairs
J
Java Code Geeks
小众软件
小众软件
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Apple Machine Learning Research
Apple Machine Learning Research
NISL@THU
NISL@THU
O
OpenAI News
The Cloudflare Blog
月光博客
月光博客
Google Online Security Blog
Google Online Security Blog
V
V2EX
罗磊的独立博客
美团技术团队
博客园 - 三生石上(FineUI控件)
Security Latest
Security Latest
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
Cyber Attacks, Cyber Crime and Cyber Security
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Cyberwarzone
Cyberwarzone
L
LINUX DO - 最新话题
Hacker News - Newest:
Hacker News - Newest: "LLM"
大猫的无限游戏
大猫的无限游戏

陈少文的网站

巨变与机遇的未来十年 Kubernetes 平台管理软件压力测试方案 使用镜像部署 Hexo 静态页面 终于等到你 - GitHub 镜像仓库服务(ghcr.io) 一起来学 Go --(6)Interface 一起来学 Go --(5)Goroutine 和 Channel 什么是函数式编程 如何在 Kubernetes 集群集成 Kata 柯里化与偏函数 使用 PyGithub 自动创建 Label 软件产品是团队能力的输出 Helm 2 、Helm 3 比较 IoT 变现 Kubernetes 中的 DNS 服务 国内的 Helm 镜像源 Harbor 使用自签证书支持 Https 访问 DevOps 工具链之 Prow 如何使用 kfctl 安装 Kubeflow VS Code 无法下载 Go 插件的工具包 工程师更应具有服务精神 你不知道的 Docker 使用技巧 使用 Docker 运行 Tensorflow 论中国 什么是左移 如何清空 Git 仓库全部历史记录 一禅小和尚 有风吹过厨房 时间的玫瑰 如何在 CentOS 安装 GPU 驱动 开发 Tips(19) 使用 Velero 备份 Kubernetes 集群 Kubernetes Cheat Sheet 开发 Tips(18) 如何构建一个 Java 工程 开发 Tips(17) KubeSpray 安装 Kubernetes 报错 ip in ansible_all_ipv4_addresses 基于 Kubernetes 和 Jenkins 搭建自动化测试系统 在 Kubernetes 上动态创建 Jenkins Slave 使用 Jenkins 进行服务拨测 开发 Tips(16) Kubernetes 签发 Ingress 证书及日常故障运维 Kubernetes 中 Deployment 的基本操作 Kubernetes 中的证书 如何使用 KubeBuilder 开发一个 Operator Kubernetes 1.6.0 安装问题汇总 镜像管理工具 -- Harbor 开发 Tips(15) Docker 如何拉取镜像 开发 Tips(14) 使用 Helm 安装 harbor 开发 Tips(13) 使用 S2I 构建云原生应用 在 Kubernetes 中使用 emptyDir、hostPath、localVolume 开发 Tips(12) 开发 Tips(11) 代码质量分析工具 SonarQube 使用 Kubeadm 安装 Kubernetes 集群 一起来学 Go --(4)常用函数 Kubernetes 中的 Ceph Kubernetes 之 Volumes Kubernetes 之 Labels、Selectors 开发 Tips(10) 开源正在重构商业模式 Kubernetes 之网络 Kubernetes 之 API 使用 Helm 和 Operator 快速部署 Prometheus Kubernetes 复杂有状态应用管理框架 -- Operator Kubernetes 的包管理器 -- Helm 一起来学 Go --(3)Go Modules 如何一步一步地优化博客方案 kubectl 实用指南 Kubernetes 中的基本概念 搭建远程 Kubernetes 开发环境 大公司和小公司的 ToB 思路 开发 Tips(9) Go 入门指南 一起来学 Go --(2)数据与逻辑结构 如何预防 Web 富文本中的 XSS 攻击 django-xss-cleaner 云工作时代 一起来学 Go --(1)背景与特点 SaaS 开发团队的不同阶段 你不知道的 Git 使用技巧 输出既服务 微服务设计 继续奔跑 开发 Tips(8) 从账户安全到二次验证 Django 性能之数据库查询优化 Django 性能之分库分表 敏捷开发之研发流程 打造一致性的团队 开发 Tips(7) Pytest 进阶学习之 Mock PaaS 部署之 buildpack Go 开发配置 领域输出才是 PaaS 的核心竞争力 Pytest 入门学习 开发 Tips(6) 如何使用 Jenkins、Docker、GitLab 搭建 Django 自动化部署流程
Django-数据迁移的几种方法(附代码)
微信公众号 · 2017-01-18 · via 陈少文的网站

Please enable Javascript to view the contents

1. 背景

在Web开发的过程当中,常会涉及多个环境(本地、测试、正式环境)之间数据的迁移。本文主要探讨在django开发过程中,可能涉及的数据迁移路径,并寻找可行的方法。

2. 场景

数据迁移对象,一共分为四个:测试环境数据库、正式环境数据库、本地开发机数据库、其他形式存在的数据源。这里其他形式存在的数据源包括:1. Excel、txt、sql、json等,以一定文本形式存在; 2. 提供访问接口的数据源。

3. 其他数据源到本地

对于 excel、txt、json 格式的数据:

  • 第一步:Python 读取文本中的数据;
  • 第二步:有两种方法。一种方法是,直接将读取的数据初始化为 django model 中的对象,保存在数据库。另一种方法是通过接口,客户端发送 POST 请求,django 中需要配置 url、编写专用的 views 函数处理这些 POST 请求,写入数据库。 后一种方法,通用性更强,兼容本地、线上的数据导入,推荐使用。

对于SQL格式的数据,可以建一个临时的数据库,然后使用django提供的工具反向创建model。通过两个model之间的字段映射关系,可以很方便的相互读写数据。

废话不多说,直接看代码!

3.1 读取 Excel

Python读取excel数据,通过接口发送给django处理。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# -*- coding: utf-8 -*-
import time
import requests
import xlrd

url = "http://127.0.0.1:8000/import_data/"
filename = "data.xlsx"
datalength = 4

def main():
    workbook = xlrd.open_workbook(filename)
    sheets1 = workbook.sheets()[0]
    for i in range(datalength):
        data1 = sheets1.row_values(i)[0]
        data2 = sheets1.row_values(i)[1]
        data3 = sheets1.row_values(i)[2]

        data = {
            "data1": data1,
            "data2": data2,
            "data3": data3
        }
        res = requests.post(url, data=data)
        print i, res
        time.sleep(1)

if __name__ == "__main__":
    main()

3.2 读取TXT

Python 读取 txt 数据,注意数据的分隔符。逐行读取数据,复制给变量。

1
2
3
with open('data.txt', 'rt') as f:
    for line in f:
        data1,data2 = line.split(' ')

3.3 读取JSON

Python读取json数据。

1
2
with open('data.json', 'r') as f:
    data = json.load(f)

3.4 读取SQL

  • 第一步,在本地新建数据库temp_db,执行data.sql,将数据导入库。
  • 第二步,使用dango提供的inspectdb命令,获得数据的model
  • 第三步,编写处理函数,转换两个model的数据
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 修改settings中默认DB的配置,将数据库名改为temp_db
# DATABASES = {
#    'default': {
#        'ENGINE': 'django.db.backends.mysql',
#        'NAME': 'temp_db',
#        'USER': 'root',
#        'PASSWORD': '',
#        'HOST': '127.0.0.1',
#        'PORT': '3306',
#    },
#}
python manage.py inspectdb > data_models.py

4. 从本地到线上

着重讨论的是本地数据库与线上数据库之前的迁移。

4.1 dumpdata与loaddata 命令

1
2
# 本地,导出django app - app_label的数据,也可以不加app_label导出全部数据
manage.py dumpdata app_label > data.json

通过 SVN 提交 data.json 至线上

线上,导入数据时不需要指定 app,因为在 json 文件 model 字段中已经指明

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
def jsonimport(request):
    import subprocess
    from django.http import HttpResponse

    cmd = '/cache/python/bin/python manage.py loaddata data.json'
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    out, err = p.communicate()
    msg = '【%s】:stdout--%s stderr--%s' % (cmd, out, err)

    try:
        return HttpResponse(msg)
    except IOError:
        return HttpResponse(u'磁盘中不存在该文件!')
    except Exception, e:
        return HttpResponse(u'系统异常!%s' % e)

4.2 subprocess执行SQL - 导入数据

本地将数据库导出为sql文件,提交到线上后,执行sql语句。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def dbimport(request):
    import subprocess
    from django.conf import settings
    from django.http import HttpResponse

    db = settings.DATABASES['default']
    dbfile = 'static/%s.sql' % db.get('NAME')
    mysql = 'mysql'
    importdb = '{dumpcmd} --user={user} ' \
             '--password={password} ' \
             '--host={host} ' \
             '--port={port} ' \
             '-f --default-character-set=utf8 ' \
             '{dbname} < {dbfile}'.format(dumpcmd=mysql,
                                          user=db.get('USER'),
                                          password=db.get('PASSWORD'),
                                          host=db.get('HOST'),
                                          port=db.get('PORT'),
                                          dbname=db.get('NAME'),
                                          dbfile=dbfile)

    p = subprocess.Popen(importdb, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    out, err = p.communicate()
    msg = '【%s】:stdout--%s stderr--%s' % (importdb, out, err)

    try:
        return HttpResponse(msg)
    except IOError:
        return HttpResponse(u'磁盘中不存在该文件!')
    except Exception, e:
        return HttpResponse(u'系统异常!%s' % e)

5. 从线上到线上

线上的数据迁移,可以走接口、保存为文本再迁移、直接复制库。

  • 通过接口来迁移数据,客户端发送GET请求数据,数据源端提供API。
  • 通过保存为文本迁移,推荐使用 json 文件。json 库提供的 load 和 dump 函数,可以很方便的读写数据。
  • 直接拷贝库,利用 subprocess 库,执行 mysqldump 和 mysql。

5.1 通过json中转

读取数据,写入json

1
2
3
4
5
6
7
8
9
def dumptojson(request):
    import json
    from django.http import HttpResponse
    data = [{'id': 1}, {'id': 2}, {'id': 3}]
    fd = json.dumps(data)
    response = HttpResponse(fd)
    response['Content-Type'] = 'application/json'
    response['Content-Disposition'] = 'attachment;filename=data.json'
    return response

读取json,写入数据

1
2
with open('data.json', 'r') as f:
    data = json.load(f)

5.2 通过dumpdata与loaddata 命令

线上的机器,不是想登就能登。上文提到了通过 views 函数执行 loaddata ,将 data.json 导入数据库。下面是执行 dumpdata,将数据从线上导出的 views 函数代码。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
def jsondump(request):
    import subprocess
    from datetime import datetime
    from django.http import HttpResponse

    file = 'data.json'
    cmd = '/cache/python/bin/python manage.py dumpdata > %s' % file
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    out, err = p.communicate()
    print '【%s】:stdout--%s stderr--%s' % (cmd, out, err)
    with open(file, 'rb') as fd:
        file_content = fd.read()
        response = HttpResponse(file_content)
        response['Content-Type'] = 'application/octet-stream'
        response['Content-Disposition'] = 'attachment;filename="%s_%s"' % (datetime.now(), file)
    return response

5.3 subprocess执行SQL - 导出数据

在上文中有通过SQL文件导入数据的代码,下面是从线上导出数据保存为SQL文件的代码。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def dump(request):
    import os, subprocess
    from datetime import datetime
    from django.conf import settings
    from django.http import HttpResponse

    db = settings.DATABASES['default']
    dbfile = 'static/%s.sql' % db.get('NAME')
    dumpcmd = 'mysqldump'
    dumpdb = '{dumpcmd} --user={user} ' \
             '--password={password} ' \
             '--host={host} ' \
             '--port={port} ' \
             '--single-transaction ' \
             '{dbname} > {dbfile}'.format(dumpcmd=dumpcmd,
                                          user=db.get('USER'),
                                          password=db.get('PASSWORD'),
                                          host=db.get('HOST'),
                                          port=db.get('PORT'),
                                          dbname=db.get('NAME'),
                                          dbfile=dbfile)
    p = subprocess.Popen(dumpdb, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    out, err = p.communicate()
    print u'【%s】:stdout--%s stderr--%s' % (dumpdb, out, err)
    ret = os.popen('/bin/ls static')
    print u'os.popen:%s' % ret.readlines()
    with open(dbfile, 'rb') as fd:
        file_content = fd.read()
        response = HttpResponse(file_content)
        response['Content-Type'] = 'application/octet-stream'
        response['Content-Disposition'] = 'attachment;filename="%s_%s.sql"' % (db.get('NAME'),
                                                                                   datetime.now())
    return response

6. 最佳实践

建议在本地开发测试阶段,以 Python 读取文本、发送 POST 请求的方式迁移数据。 数据再次迁移至测试、正式环境时,只需要修改接口 url 即可。但是要注意,接口的安全性,控制接口的频率。

测试环境的测试数据迁移正式环境,可以考虑使用 subprocess 库进行处理。如果对线上环境不确定,可以结合 webshell 等工具,先进行探测,减少调试时间。


微信公众号