Django中REST framework與MongoDB的搭配使用
Django框架下,因其功能強大可為廣大使用者提供各種資料庫的配套使用方法。由於要學習學長的專案,所以我需要學習MongoDB資料庫搭配REST framework的使用,在網上查找了一些資料後發現大部分資料都是關於其自帶的sqlite3的,所以在這裡分享一下我在網上查詢到的一些MongoDB搭配REST framework的使用方法。
新增依賴
python的第三方庫非常的強大,可以說是什麼都有,只有你想不到的。要在REST framework中使用MongoDB就必須新增以下兩個依賴庫。
pip install djangorestframework pip Django-rest-framework-mongoengine 3.3.1
想要具體瞭解rest_framework_mongoengine的api詳見http://umutbozkurt.github.io/django-rest-framework-mongoengine/index.html
建立專案
然後當然就是開始建立你的專案了。建立專案具體過程我就不囉嗦了。
#建立專案vis23
django-admin.py startproject vis23
#建立APP datas
python manage.py startapp datas
註冊APP
在datas的settings中找到INSTALLED_APPS
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', #新增 'rest_framework', 'rest_framework_mongoengine', 'datas', ]
向MongoDB中匯入資料
匯入資料的具體過程我也不詳細說了,在我的上一篇部落格中有寫到。這裡我匯入的是我們專案中17年的資料。
建立一個名為data2mongo的.py檔案,具體程式碼如下:
from pymongo import MongoClient from vis.settings import DBCONFIG import csv class Data1: filename = '網咖資訊.csv' path = 'C:\\Users\\Administrator\\Desktop\\2017\\' c_raw1 = 'raw_data1' colname = ['siteid', 'title', 'lng', 'lat'] res = [] max_len = 100000 def __init__(self): self.files = [] self.files.append(self.filename) self.client = MongoClient(DBCONFIG['HOST'], DBCONFIG['PORT']) self.db = self.client.__getattr__(DBCONFIG['NAME']) self.dst_raw1 = self.db[self.c_raw1] def __del__(self): self.client.close() @staticmethod def convert_fileaffix(fileaffix): if len(fileaffix) == 0: return '' while fileaffix[0] == '.': fileaffix = fileaffix[1:] if '.' in fileaffix: return None else: return fileaffix def data1(self): self.dst_raw1.remove({}) self.res.clear() print('正在處理檔案:%s' % (self.path + self.filename)) with open(self.path + self.filename) as infile: reader = csv.reader(infile) next(reader) for row in reader: fileaffix = self.convert_fileaffix(str(row[3])) if fileaffix is None: continue self.res.append({ 'siteid': str(row[0]), 'title': str(row[1]), 'lng': str(row[2]), 'lat': str(row[3]), }) if self.res.__len__() == self.max_len: self.dst_raw1.insert_many(self.res) self.res.clear() if self.res.__len__() > 0: self.dst_raw1.insert_many(self.res) self.res.clear() class Data2: filename = 'hydata_swjl_{}.csv' path = 'C:\\Users\\Administrator\\Desktop\\2017\\' count = range(0, 2) c_raw2 = 'raw_data2' colname = ['personid', 'siteid', 'xb', 'customername', 'onlinetime', 'offlinetime', 'areaid', 'birthday'] res = [] max_len = 100000 def __init__(self): self.files = [] for i in self.count: self.files.append(self.filename.format(i)) self.client = MongoClient(DBCONFIG['HOST'], DBCONFIG['PORT']) self.db = self.client.__getattr__(DBCONFIG['NAME']) self.dst_raw2 = self.db[self.c_raw2] def __del__(self): self.client.close() @staticmethod def convert_fileaffix(fileaffix): if len(fileaffix) == 0: return '' while fileaffix[0] == '.': fileaffix = fileaffix[1:] if '.' in fileaffix: return None else: return fileaffix def data2(self): self.dst_raw2.remove({}) self.res.clear() for i in self.count: print('正在處理檔案:%s' % (self.path + self.filename.format(i))) with open(self.path + self.filename.format(i)) as infile: reader = csv.reader(infile) next(reader) for row in reader: fileaffix = self.convert_fileaffix(str(row[3])) if fileaffix is None: continue self.res.append({ 'personid': str(row[0]), 'siteid': str(row[1]), 'xb': str(row[2]), 'customername': str(row[3]), 'onlinetime': str(row[4]), 'offlinetime': str(row[5]), 'areaid': str(row[6]), 'birthday': str(row[7]), }) if self.res.__len__() == self.max_len: self.dst_raw2.insert_many(self.res) self.res.clear() if self.res.__len__() > 0: self.dst_raw2.insert_many(self.res) self.res.clear()
這裡解釋一下程式碼:其中, from vis.settings import DBCONFIG 中的 DBCONFIG 是我在datas的setting中定義的一個方便連線MongoDB的函式;因為我要匯入的一共是三張.csv 的表,分別是 網咖資訊.csv,hydata_swjl_0.csv,hydata_swjl_1.csv,其中後兩表表內格式一致,所以建立了兩個類用於分別匯入。
這裡需要特別注意的是:為了去掉表頭,使用了
reader = csv.reader(infile)
next(reader)
這兩句話,它的作用是在匯入表時去掉表頭中的文字,但在執行時總是報錯,錯誤資訊為:
next(reader)
UnicodeDecodeError: 'gbk' codec can't decode byte 0xb7 in position 112: illegal multibyte sequence
這是由於讀取檔案的字元編碼問題,在with open()中這樣改一下就好了
with open(self.path + self.filename.format(i), 'r', encoding='UTF-8') as infile:
當然data2Mongo只是匯入的方法,要執行還得需要一個函式來呼叫它,handles.py,程式碼如下:
from data2mongo import Data1
from data2mongo import Data2
import time
if __name__ == '__main__':
start = time.clock()
tomongo1 = Data1()
tomongo1.data1()
tomongo2 = Data2()
tomongo2.data2()
到這之後,終於該進入正題了。在此之前我們需要在datas的setting中新增兩句話,並且將DATABASES中的類容設定為空
DATABASES = { 'default': { 'ENGINE': None, #設定為空 } } from mongoengine import connect #連線MongoDB的庫 connect('vis') #連線vis資料庫
編寫Datas
1.建立模型,使用mongoengine.Document。一般在編寫api的時候我們在models中都是這樣寫的
class Student(models.Model):
但由於我們要使用mongoDB所以我們需要這樣改一下class data1(Document):
class data1(Document):
具體程式碼如下:
from __future__ import unicode_literals
from mongoengine import *
# Create your models here.
connect('vis', host='127.0.0.1', port=27017) #連線資料庫
class data1(Document):
siteid = StringField(max_length=45)
title = StringField(max_length=45)
lng = StringField(max_length=45)
lat = StringField(max_length=45)
meta = {'collection': 'raw_data1'} #資料庫中的集合
def __unicode__(self):
return self.name
class data2(Document):
personid = StringField(primary_key=True)
siteid = StringField(max_length=45)
xb = StringField(max_length=45)
customername = StringField(max_length=45)
onlinetime = StringField(max_length=45)
offlinetime = StringField(max_length=45)
areaid = StringField(max_length=45)
birthday = StringField(max_length=45)
meta = {'collection': 'raw_data2'} #資料庫中的集合
def __unicode__(self):
return self.name
2.編寫序列,對serializer需要稍作變化,使用rest_framework_mongoengine.serializers
from rest_framework_mongoengine import serializers
from . import models
class data1Serializer(serializers.DocumentSerializer):
class Meta:
model = models.data1
fields = '__all__'
class data2Serializer(serializers.DocumentSerializer):
class Meta:
model = models.data2
fields = '__all__'
3.在view中同理
from . import models
from . import serializers
from rest_framework_mongoengine import generics
class data1View(generics.ListCreateAPIView):
queryset = models.data1.objects.all().order_by('siteid')
serializer_class = serializers.data1Serializer
class data2View(generics.ListCreateAPIView):
queryset = models.data2.objects.all().order_by('personid')
serializer_class = serializers.data2Serializer
4.設定路由
(1)在datas中的urls中定義路由
from django.urls import path
from .views import data1View
from .views import data2View
urlpatterns = [
path('data1/', data1View.as_view(), name='data1'),
path('data2/', data2View.as_view(), name='data2')
]
(2)在總路由中新增路由地址
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('datas.urls')),
]
做完這些之後,我們就可以運行了
python manage.py runserver
在瀏覽器輸入http://127.0.0.1:8000/api/data1或data2 我們就能看到:
這樣一個基本的api就實現了,當然其中我們可以看到顯示的字元有一些問題,這是由於當初向資料庫中匯入資料是定義的型別的問題,後面我們會加以改正。