Django数据库导入导出

Django数据库导入

从网上下载的一些数据,Excel表,xml文件,txt文件等有时候我们想把他们导入数据库,应该如何操作呢?

备注:你可能会问数据从哪里来,比如你用python从以前的blog上获取过来的,想到如现在的博客,或者别人整理好的数据,一个个地从网站后台复制黏贴太麻烦,这就是批量导入的必要性。
建议不要先看源码,按教程一步步做下去,遇到问题再试试源代码,直接复制粘贴,很快会忘记,自己动手打一遍

我们新建一个项目mysite,在新建一个app,名称为blog

django-admin.py startproject mysite
cd mysite/
python manage.py startapp blog

把blog中的models.py更改为以下内容:

from django.db import models

# Create your models here.

class Blog(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    
    def __str__(self):
        return self.title

不要忘记把blog加入到settings.py中的INSTALLED_APPS中

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',  # 添加上blog这个app
]

一、同步数据库,创建相应的表

python manage.py makemigrations
# 看到以下内容:
Migrations for 'blog':
  blog/migrations/0001_initial.py
    - Create model Blog


student@student-VirtualBox:~/mysite$ python manage.py migrate
# 看到以下内容:
Operations to perform:
  Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying blog.0001_initial... OK
  Applying sessions.0001_initial... OK

二、输入python manage.py shell
进入该项目的django环境的终端
先说说如何使用命令新增一篇文章:

from blog.models import Blog
Blog.objects.create(title="The first blog of my site",content="I am writing my blog on Terminal")
# <Blog: The first blog of my site>

这样就新增了一篇博文,我们查看一下:

Blog.objects.all()

<QuerySet [<Blog: The first blog of my site>]>

还有两种方法:

 blog2 = Blog()
 blog2.title = "title 2"
 blog2.content = "content 2"
 blog2.save()
  或者
 blog2=Blog(title="title2",content="content 2")
 blog2.save()

后面两种方法也很重要,尤其是在用在修改数据的时候,要记得最后要保存一下blog.save(),第一种Blog.objects.create()是自动保存的。
三、批量导入
比如我们要导入一个文本,里面是标题的内容。中间用四个*隔开的,示例(pldblog.txt):

title 1****content 1
title 2****content 2
title 3****content 3
title 4****content 4
title 5****content 5
title 6****content 6
title 7****content 7
title 8****content 8
title 9****content 9

在终端导入有时候有些不方便,我们在最外面哪个mysite目录下写个脚本,叫txt2db.py,把pldblog.txt也放在mysite下:

#!/usr/bin/env python
#coding:utf-8
  
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
  
'''
Django 版本大于等于1.7的时候,需要加上下面两句
import django
django.setup()
否则会抛出错误 django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.
'''
  
import django
if django.VERSION >= (1, 7):#自动判断版本
    django.setup()
  
  
def main():
    from blog.models import Blog
    f = open('pldblog.txt')
    for line in f:
        title,content = line.split('****')
        Blog.objects.create(title=title,content=content)
    f.close()
  
if __name__ == "__main__":
    main()
    print('Done!')

好了,我们在终端运行它:

python txt2db.py
# 运行完后显示 一个 Done! 导入完成!

四、导入数据重复解决办法

如果你导入数据过多,导入时出错了,或者你手动停止了,导入了一部分,还有一部分没有导入。或者你再次运行上面的命令,你会发现数据重复了,怎么办呢?

django.db.models中还有一个函数叫get_or_create()有就获取过来,没有就创建,用它可以避免重复,但是速度可以会慢些,因为要先尝试获取,看看有没有

# 只要把上面的
Blog.objects.create(title=title,content=content)

# 换成下面的就不会重复导入数据了
Blog.objects.get_or_create(title=title,content=content)
# 返回值是(BlogObject,True/False)新建时返回True,已经存在时返回False。

五、用fixture导入

最常见的fixture文件就是python manage.py dumpdata导出的文件,示例如下:

[
  {
    "model": "myapp.person",
    "pk": 1,
    "fields": {
      "first_name": "John",
      "last_name": "Lennon"
    }
  },
  {
    "model": "myapp.person",
    "pk": 2,
    "fields": {
      "first_name": "Paul",
      "last_name": "McCartney"
    }
  }]

你也可以根据自己的models,创建这样的json文件,然后用python manage.py loaddata fixture.json导入

可以写一个脚本,把要导入的数据转换成json文件,这样导入也会更快些!

六、Model.objects.bulk_create()更快更方便

#!/usr/bin/env python
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
  
def main():
    from blog.models import Blog
    f = open('oldblog.txt')
    BlogList = []
    for line in f:
        title,content = line.split('****')
        blog = Blog(title=title,content=content)
        BlogList.append(blog)
    f.close()
      
    Blog.objects.bulk_create(BlogList)
  
if __name__ == "__main__":
    main()
    print('Done!')

由于Blog.objects.create()每保存一条就执行一次SQL,而bulk_create()是执行一条SQL存入多条数据,做会块很多!当然用列表解析代替for循环会更快!!

#!/usr/bin/env python
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
  
def main():
    from blog.models import Blog
    f = open('oldblog.txt')
      
    BlogList = []
    for line in f:
        parts = line.split('****')
        BlogList.append(Blog(title=parts[0], content=parts[1]))
          
    # 以上四行 也可以用 列表解析 写成下面这样
    # BlogList = [Blog(title=line.split('****')[0], content=line.split('****')[1]) for line in f]
      
    Blog.objects.bulk_create(BlogList)
  
if __name__ == "__main__":
    main()
    print('Done!')

当然也可以利用数据中的导出,在导入的方法,  
Django 数据迁移
Django数据库不同数据库,SQLite3,MySQL,PostgreSQL之间数据迁移的方案,以及不同机器之间的迁移方案

一、简单的数据导出与导入(简单的迁移)
1、django项目提供了一个导出的方法python manage.py dumpdata,不指定appname时默认为导出所有的app

python manage.py dumpdata [appname] > appname_data.json

比如我们有一个项目叫mysite,里面有一个app叫blog,我们想导出blog的所有数据

python manage.py dumpdata blog > blog_dump.json

2、数据导入,不需要指定appname

python manage.py loaddata blog_dump.json

备注:一些常用的

python manage.py dumpdata auth > auth.json # 导出用户数据

优点:可以兼容各种支持的数据库,也就是说,以前用的是SQLite3,可以导出后,用这种方法导入到MySQL,PostgreSQL等数据库,反过来也可以。
缺点:数据量大的时候,速度相对较慢,表的关系比较复杂的时候可以导入不成功。

二、数据库的迁移

2、1用Django自带的命令
比如早期我们为了开发方便,用sqlite3数据库,后来发现网站数据太多,sqlite3性能有点跟不上了,想换成postgreSQL或者MySQL的时候。
如果我还使用上面的命令,如果你运气好的话,也许会导入成功,流程如下:

2.1.1 从原来的整个数据库导出所有数据

python manage.py dumpdata > mysite_all_data.json

2.1.2 将mysite_all_data.json传送到另一个服务器或者电脑上导入

python manage.py loaddata mysite_all_data.json

如果你运气好的话可能会导入完成,但是往往不那么顺利,原因如下:
a)我们在写models的时候如果用到CharField,就一定要写max_length,在sqlite3中是不检查这个最大长度的,你写最大运行长度为100.你网数据库放10000个,sqlite3都不报错,而且不截断数据的长度,这似乎是slite3的优点,但是也给从sqlite3导入其他数据库带来了困难,因为MySQL和PostgreSQL数据库都会检查最大长度,超出时就报错!
b)Django自带的contentType会导致出现一些问题
用上面的方法只迁移一个app应该问题不大,但是如果有用户,用户组挂钩,事情往往变得糟糕!如果导入后没有对数据进行修改,你可以重新导入,可能还要块一些,如果是手动在后人输入或者修改过,这种方法就不适用了
2.2、用数据库自带的导出导入命令
假定Django用的数据库名称为wulaoer
2.2.1 在PostgreSQL中:

# 导出数据库 zqxt 到 wulaoer.sql 文件中
pg_dump wulaoer > wulaoer.sql

# 导入数据库到 新的服务器
psql wulaoer -f wulaoer.sql

#注意:数据导入导出可能需要数据库超级权限,用 sudo su postgres 切换到数据库超级用户 postgres

2.2.2 在MySQL中:
使用网页工具,比如phpMyAdmin导入导出很简单,这里就不说了,主要就说一下命令行如何操作:

# 导出数据库 wulaoer 到 wulaoer.sql 文件中
mysqldump -u username -p --database wulaoer > wulaoer.sql

# 导入数据库到 新的服务器
mysql -u username -p

输入密码进入 MySQL 命令行
 source /path/to/wulaoer.sql

总结:其他的数据库,请自行搜索如何导入导出,整个数据库导出的好处就是对数据之间的关系处理比较省事,比如自强学堂里面的很多教程,上篇和下一篇是一个一对一的关系,这样的话用python manage.py dumpdata无法导出教程与教程的关系,但是数据库整个导出就没有任何问题,当然也可以写一个脚本导出关系再导入。Django自带的python manage.py dumpdata和python manage.py loaddata最大的好处就是可以跨站数据库进行导入导出。
Django 多数据库联用
以下是讲述在一个django project中使用多个数据库的方法,多个数据库的联用以及多数据库时数据库导入导出的方法。
直接给出一种简单的方法,想了解更多可以到官方,点击此处  
代码文件下载:
project_name.zip  
1、每个app都可以单独设置一个数据库
settings.py中有数据库的相关设置,有一个默认的数据库default,我们可以再加一些其他的,比如:

# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    },
    'db1': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'dbname1',
        'USER': 'your_db_user_name',
        'PASSWORD': 'yourpassword',
        "HOST": "localhost",
    },
    'db2': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'dbname2',
        'USER': 'your_db_user_name',
        'PASSWORD': 'yourpassword',
        "HOST": "localhost",
    },
}
  
# use multi-database in django
# add by WeizhongTu
DATABASE_ROUTERS = ['project_name.database_router.DatabaseAppsRouter']
DATABASE_APPS_MAPPING = {
    # example:
    #'app_name':'database_name',
    'app1': 'db1',
    'app2': 'db2',
}

在project_name文件夹中存放database_route.py文件,内容如下:

# -*- coding: utf-8 -*-
from django.conf import settings
  
DATABASE_MAPPING = settings.DATABASE_APPS_MAPPING
  
  
class DatabaseAppsRouter(object):
    """
    A router to control all database operations on models for different
    databases.
  
    In case an app is not set in settings.DATABASE_APPS_MAPPING, the router
    will fallback to the `default` database.
  
    Settings example:
  
    DATABASE_APPS_MAPPING = {'app1': 'db1', 'app2': 'db2'}
    """
  
    def db_for_read(self, model, **hints):
        """"Point all read operations to the specific database."""
        if model._meta.app_label in DATABASE_MAPPING:
            return DATABASE_MAPPING[model._meta.app_label]
        return None
  
    def db_for_write(self, model, **hints):
        """Point all write operations to the specific database."""
        if model._meta.app_label in DATABASE_MAPPING:
            return DATABASE_MAPPING[model._meta.app_label]
        return None
  
    def allow_relation(self, obj1, obj2, **hints):
        """Allow any relation between apps that use the same database."""
        db_obj1 = DATABASE_MAPPING.get(obj1._meta.app_label)
        db_obj2 = DATABASE_MAPPING.get(obj2._meta.app_label)
        if db_obj1 and db_obj2:
            if db_obj1 == db_obj2:
                return True
            else:
                return False
        return None
  
    def allow_syncdb(self, db, model):
        """Make sure that apps only appear in the related database."""
  
        if db in DATABASE_MAPPING.values():
            return DATABASE_MAPPING.get(model._meta.app_label) == db
        elif model._meta.app_label in DATABASE_MAPPING:
            return False
        return None

这样就实现了指定的app使用指定的数据库了,当然你也可以多个sqlite3一起使用,相当于可以给每个app都可以单独设置一个数据库!如果不设置或者有设置的app就会自动使用默认的数据库

2、多个数据库联用时数据库导入导出

使用的时候和一个数据库的区别是:
如果不是defalut(默认数据库)要在命令后加--database=数据库对应的settings.py中的名称 如: --database=db1 或 --database=db2
数据库同步(创建表)

python manage.py syncdb #同步默认的数据库,和原来的没有区别

#同步数据库 db1 (注意:不是数据库名是db1,是settings.py中的那个db1,不过你可以使这两个名称相同,容易使用)

python manage.py syncdb --database=db1

数据导出

python manage.py dumpdata app1 --database=db1 > app1_fixture.json
python manage.py dumpdata app2 --database=db2 > app2_fixture.json
python manage.py dumpdata auth > auth_fixture.json

数据导入

python manage.py loaddata app1_fixture.json --database=db1
python manage.py loaddata app2_fixture.json --database=db2
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容