從網上下載的一些資料,excel表格,xml檔案,txt檔案等有時候我們想把它匯入資料庫,應該如何操作呢?
以下操作符合 Django版本為 1.6 ,兼顧 Django 1.7, Django 1.8 版本,理論上Django 1.4, 1.5 也沒有問題,沒有提到的都是預設值
備註:你可能會問資料從哪兒來的,比如你用python從以前的blog上獲取過來的,想匯入現在的部落格,或者別人整理好的資料,或者你自己整理的excel表,一個個地在網站後臺複製貼上你覺得好麼?這就是批量匯入的必要性。
下載本教程原始碼: mysite.zip
建議先不要看原始碼,按教程一步步做下去,遇到問題再試試原始碼,直接複製貼上,很快就會忘掉,自己動手打一遍
我們新建一個專案 mysite, 再新建一個 app,名稱為blog
1
2
3
|
django-admin.py startproject mysite cd mysite python manage.py startapp blog |
把 blog 中的 models.py 更改為以下內容
1
2
3
4
5
6
7
8
9
10
11
|
#!/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 中。
1
2
3
4
5
6
7
|
# Application definition INSTALLED_APPS = ( ... # 新增上 blog 這個 app 'blog' , ) |
一,同步資料庫,建立相應的表
1
|
python manage.py syncdb |
Django 1.6以下版本會看到:
Django 建立了一些預設的表,注意後面那個紅色標記的blog_blog是appname_classname的樣式,這個表是我們自己寫的Blog類建立的
Django 1.7.6及以上的版本會看到:(第六行即為建立了對應的blog_blog表)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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' ): tu Email address: Password: Password (again): Superuser created successfully. |
二,輸入 python manage.py shell
進入該專案的django環境的終端(windows如何進入對應目錄?看 Django環境搭建 的 3.2 部分)
先說如何用命令新增一篇文章:
1
2
3
4
|
$ 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" ) |
這樣就新增了一篇博文,我們檢視一下
1
2
|
>>> Blog.objects.all() # 獲取所有blog [<Blog: The first blog of my site>] |
還有兩種方法(這兩種差不多):
1
2
3
4
5
6
7
|
>>> 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()是自動儲存的。
三,批量匯入
比如我們要匯入一個文字,裡面是標題和內容,中間用四個*隔開的,示例(oldblog.txt):
1
2
3
4
5
6
7
8
9
|
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,把 oldblog.txt 也放在mysite下
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
|
#!/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!' ) |
這裡如果oldblog.txt要全地址的話要這樣:
open("C:\\Users\\Rajrishi\\Documents\\MyJava\\text.txt") # meh
open(r"C:\Users\Rajrishi\Documents\MyJava\text.txt") # better
open("C:/Users/Rajrishi/Documents/MyJava/text.txt") # also possible
可能是因為\有轉義字元的意思,所以settings裡面都是用/
好了,我們在終端執行它
1
2
|
python txt2db.py # 執行完後顯示 一個 Done! 匯入完成! |
執行完畢後會打出一個 "Done!", 資料已經全部匯入!
四,匯入資料重複 解決辦法
如果你匯入資料過多,匯入時出錯了,或者你手動停止了,匯入了一部分,還有一部分沒有匯入。或者你再次執行上面的命令,你會發現資料重複了,怎麼辦呢?
django.db.models 中還有一個函式叫 get_or_create() 有就獲取過來,沒有就建立,用它可以避免重複,但是速度可以會慢些,因為要先嚐試獲取,看看有沒有
只要把上面的
1
|
Blog.objects.create(title=title,content=content) |
換成下面的就不會重複匯入資料了
1
|
Blog.objects.get_or_create(title=title,content=content) |
返回值是(BlogObject, True/False) 新建時返回 True, 已經存在時返回 False。
更多資料庫API的知識請參見官網文件:QuerySet API
五, 用fixture匯入
最常見的fixture檔案就是用python manage.py dumpdata 匯出的檔案,示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
[ { "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() 更快更方便
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#!/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 迴圈會更快!!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#!/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])) f.close() # 以上四行 也可以用 列表解析 寫成下面這樣 # BlogList = [Blog(title=line.split('****')[0], content=line.split('****')[1]) for line in f] Blog.objects.bulk_create(BlogList) if __name__ == "__main__" : 這招有點像c語言的main函式定義入口 main() print( 'Done!' ) |