Django: 之數據庫導入、遷移和聯用


Django 數據庫導入

從網上下載的一些數據,excel表格,xml文件,txt文件等有時候我們想把它導入數據庫,應該如何操作呢?

以下操作符合 Django版本為 1.6 ,兼顧 Django 1.7, Django 1.8 版本,理論上Django 1.4, 1.5 也沒有問題,沒有提到的都是默認值

備注:你可能會問數據從哪兒來的,比如你用python從以前的blog上獲取過來的,想導入現在的博客,或者別人整理好的數據,或者你自己整理的excel表,一個個地在網站后台復制粘貼你覺得好么?這就是批量導入的必要性。

建議先不要看源碼,按教程一步步做下去,遇到問題再試試源代碼,直接復制粘貼,很快就會忘掉,自己動手打一遍

我們新建一個項目mysite,在新建一個app,名稱為blog

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

把blog中的models.py更改為一下內容

#!/usr/bin/python
#coding:utf-8
 
from django.db import models
 
class Blog(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
     
    def __unicode__(self):
        return self.title

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

# Application definition
INSTALLED_APPS = (
    ...
     
    # 添加上 blog 這個 app
    'blog',
)

一、同步數據庫,創建相應的表

python manage.py syncdb

Django 1.6以下版本會看到:

Django創建了一些默認的表,注意后面哪個紅色標記的blog_blog是appname_classname的樣式,這個表是我們自己寫的Blog類創建的

Django 1.7.6及以上的版本會看到:(第六行即創建了對應的blog_blog表)

Operations to perform:
  Synchronize unmigrated apps: blog
  Apply all migrations: admin, contenttypes, auth, sessions
Synchronizing apps without migrations:
  Creating tables...
    Creating table blog_blog
  Installing custom SQL...
  Installing indexes...
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying sessions.0001_initial... OK
 
You have installed Django's auth system, and don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username (leave blank to use 'tu'): wulaoer
Email address: 
Password: 
Password (again): 
Superuser created successfully.

二、輸入python manage.py shell  

進入該項目的django環境的終端(windows如何進入對應目錄?看Django環境搭建的3.2部分)

先說說如何使用命令新增一篇文章:

$ python manage.py shell
>>> from blog.models import Blog
>>> Blog.objects.create(title="The first blog of my site", 
                        content="I am writing my blog on Terminal")

這樣就新增了一篇博文,我們查看以下  

>>> Blog.objects.all() # 獲取所有blog
[<Blog: The first blog of my site>]

還有兩種方法(這兩種差不多):

>>> blog2 = Blog()
>>> blog2.title = "title 2"
>>> blog2.content = "content 2"
>>> blog2.save()
或者
>>> blog2 = Blog(title="title 2",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,把lodblog.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('oldblog.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。

更多數據庫API的知識請參見官網文檔:QuerySet API  

五、用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導入

詳見:https://docs.djangoproject.com/en/dev/howto/initial-data/

可以寫一個腳本,把要導入的數據轉換成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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM