Django模型-数据库配置
上一章介绍了Django model的一些基本理念,接下来让我们开始Django数据库层的探索。首先,我们需要做些初始配置;我们需要告诉Django使用什么数据库以及如何连接数据库。
Django 对各种数据库提供了很好的支持,包括:PostgreSQL、MySQL、SQLite、Oracle。
Django 为这些数据库提供了统一的调用API。 我们可以根据自己业务需求选择不同的数据库。
备注:本章不介绍相关数据库在服务器上的安装及激活等。我们假定你已经完成了数据库服务器的安装和激活,并且在其中创建了数据库(例如,用CREATE DATABASE语句)。如果你使用SQLite,则不需要这不安装,因为SQLite使用文件系统上的独立文件来存储数据。
SQLite
SQLite是Django默认的数据库,当我们创建一个Django项目后,配置文件里就已经帮我们配置好了SQLite。
#settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
当我们使用python manage.py makemigrations
python manage.py migrate myapp
应用数据库后,会在项目目录下看到db.sqlite3
,这就是项目的SQLite
数据库文件,可使用sqlite3连接使用。
➜ myproject ls
db.sqlite3 manage.py myapp myproject
➜ myproject sqlite3 db.sqlite3
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
sqlite>
MySQL
数据库切换成Mysql需要我们对配置进行修改
#settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'myproject', #数据库名字,
'USER': 'root', #数据库登录用户名
'PASSWORD': '123456', #数据库登录密码
'HOST': 'localhost', #数据库所在主机(项目中写真实主机地址)
'PORT': '3306', #数据库端口
}
}
在python2
中,使用pip install mysql-python
进行安装连接MySQL的库,使用时 import MySQLdb
进行使用.
在python3
中,改变了连接库,改为了pymysql
库,使用pip install pymysql
进行安装,直接导入即可使用
但是在Django
中, 连接数据库时使用的是MySQLdb
库,这在与python3
的合作中就会报以下错误了:
django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module: No module named 'MySQLdb'
解决办法:找到项目配置目录下的init.py
➜ myproject ls
db.sqlite3 manage.py myapp myproject
➜ myproject vim myproject/__init__.py
添加以下代码:
import pymysql
pymysql.install_as_MySQLdb()
当然,首先你得安装这个模块,pip install pymysql
。。。
Oracle
数据库切换成Oracle需要我们对配置进行修改
#settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.oracle',
'NAME': 'myproject', #数据库名字,
'USER': 'root', #数据库登录用户名
'PASSWORD': '123456', #数据库登录密码
'HOST': 'localhost', #数据库所在主机(项目中写真实主机地址)
'PORT': '3306', #数据库端口
}
}
如果使用Oracle,需要安装cx_Oracle库,可以从https://pypi.python.org/pypi/cx_Oracle/获得。 要用4.3.1或更高版本,但要避开5.0,这是因为这个版本的驱动有bug。
PostgreSQL
数据库切换成PostgreSQL需要我们对配置进行修改
#settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'myproject', #数据库名字,
'USER': 'root', #数据库登录用户名
'PASSWORD': '123456', #数据库登录密码
'HOST': 'localhost', #数据库所在主机(项目中写真实主机地址)
'PORT': '3306', #数据库端口
}
}
安装第三方库:
pip install psycopg2
数据库配置错误信息
错误信息 | 解决办法 |
---|---|
You haven’t set the DATABASE_ENGINE setting yet. | 不要以空字符串配置DATABASE_ENGINE 的值。 表格 5-1 列出可用的值。 |
Environment variable DJANGO_SETTINGS_MODULE is undefined. | 使用python manager.py shell 命令启动交互解释器,不要以python 命令直接启动交互解释器。 |
Error loading _ module: No module named _. | 未安装合适的数据库适配器 (例如, psycopg 或 MySQLdb )。Django并不自带适配器,所以你得自己下载安装。 |
_ isn’t an available database backend. | 把DATABASE_ENGINE 配置成前面提到的合法的数据库引擎。 也许是拼写错误? |
database _ does not exist | 设置DATABASE_NAME 指向存在的数据库,或者先在数据库客户端中执行合适的CREATE DATABASE 语句创建数据库。 |
role _ does not exist | 设置DATABASE_USER 指向存在的用户,或者先在数据库客户端中执创建用户。 |
could not connect to server | 查看DATABASE_HOST和DATABASE_PORT是否已正确配置,并确认数据库服务器是否已正常运行。 |
MongoDB
上述都是Django默认支持的关系型数据库,对于非关系型的数据库,例如MongoDB
,是不支持的。不支持不代表不能用,只是如果在Django中使用MongoDB,需要自己动手写相应的扩展。
适配器
选择pymongo
作为我们MongoDB
的适配器
pip install pymongo
数据库配置
#settings.py
MONGODB_CONFIG = {
'host': '127.0.0.1',
'port': 27017,
'db_name': 'test',
'username': None,
'password': None
}
自定义数据连接
#connection.py
import pymongo
import sys
import traceback
from settings import MONGODB_CONFIG
class Singleton(object):
'''单例模式'''
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
orig = super(Singleton, cls)
cls._instance = orig.__new__(cls, *args, **kwargs)
return cls._instance
class MongoConn(Singleton):
'''单例并连接mongodb'''
def __init__(self):
try:
self.conn = pymongo.MongoClient(MONGODB_CONFIG['host'], MONGODB_CONFIG['port'])
self.db = self.conn[MONGODB_CONFIG['db_name']] # connect db
self.username=MONGODB_CONFIG['username']
self.password=MONGODB_CONFIG['password']
if self.username and self.password:
self.connected = self.db.authenticate(self.username, self.password)
else:
self.connected = True
except Exception:
print(traceback.format_exc())
print('Connect Statics Database Fail.')
sys.exit(1)
自定义数据操作api
#api.py
import traceback
import logging
from connection import MongoConn
LOGGER = logging.getLogger("mongodb") # 为loggers中定义的名称
def check_connected(conn):
'''检查是否连接成功'''
if not conn.connected:
raise NameError('stat:connected Error')
def save(table, value):
'''一次操作一条记录,根据‘_id’是否存在,决定插入或更新记录'''
try:
my_conn = MongoConn()
check_connected(my_conn)
my_conn.db[table].save(value)
except Exception:
LOGGER.error(traceback.format_exc())
def del_one(table, value):
'''
删除指定记录
'''
try:
my_conn = MongoConn()
check_connected(my_conn)
my_conn.db[table].delete_one(value)
except Exception:
LOGGER.error(traceback.format_exc())
def del_all(table, value):
'''
删除所有匹配的记录
返回了一个DeleteResult对象。这个对象报告了被删除的文档数目。
要查看被删除的文档数目,通过访问DeleteResult对象的deleted_count属性
'''
try:
my_conn = MongoConn()
check_connected(my_conn)
result = my_conn.db[table].delete_many(value)
except Exception:
LOGGER.error(traceback.format_exc())
return result
def insert(table, value):
# 可以使用insert直接一次性向mongoDB插入整个列表,也可以插入单条记录,但是'_id'重复会报错
try:
my_conn = MongoConn()
check_connected(my_conn)
my_conn.db[table].insert(value, continue_on_error=True)
except Exception:
LOGGER.error(traceback.format_exc())
def update(table, conditions, value, s_upsert=False, s_multi=False):
'''
condition: update的查询条件
value: update的对象和一些更新的操作符(如$,$inc...)等
upsert : 如果不存在update的记录,是否插入记录.默认是false,不插入。
multi : 默认是false,只更新找到的第一条记录.若为true,
就把按条件查出来多条记录全部更新。
'''
try:
my_conn = MongoConn()
check_connected(my_conn)
my_conn.db[table].update(conditions, value, upsert=s_upsert, multi=s_multi)
except Exception:
LOGGER.error(traceback.format_exc())
def upsert_mary(table, datas):
'''
批量更新插入,根据‘_id’更新或插入多条记录。
把'_id'值不存在的记录,插入数据库。'_id'值存在,则更新记录。
如果更新的字段在mongo中不存在,则直接新增一个字段
'''
try:
my_conn = MongoConn()
check_connected(my_conn)
bulk = my_conn.db[table].initialize_ordered_bulk_op()
for data in datas:
_id = data['_id']
bulk.find({'_id': _id}).upsert().update({'$set': data})
bulk.execute()
except Exception:
LOGGER.error(traceback.format_exc())
def upsert_one(table, data):
'''
更新插入,根据‘_id’更新一条记录,如果‘_id’的值不存在,则插入一条记录
'''
try:
my_conn = MongoConn()
check_connected(my_conn)
query = {'_id': data.get('_id', '')}
if not my_conn.db[table].find_one(query):
my_conn.db[table].insert(data)
else:
data.pop('_id') #删除'_id'键
my_conn.db[table].update(query, {'$set': data})
except Exception:
LOGGER.error(traceback.format_exc())
def find_one(table, value):
'''
根据条件进行查询,返回一条记录
'''
try:
my_conn = MongoConn()
check_connected(my_conn)
return my_conn.db[table].find_one(value)
except Exception:
LOGGER.error(traceback.format_exc())
def find(table, value=None):
'''
根据条件进行查询,返回所有记录
当value为None时,默认返回table里所有记录
'''
try:
my_conn = MongoConn()
check_connected(my_conn)
return my_conn.db[table].find(value)
except Exception:
LOGGER.error(traceback.format_exc())
def select_colum(table, value, colum):
'''
查询指定列的所有值
'''
try:
my_conn = MongoConn()
check_connected(my_conn)
return my_conn.db[table].find(value, {colum:1})
except Exception:
LOGGER.error(traceback.format_exc())
def insert_infographic_block(mongdb_id,page_id,block):
'''
插入一个infographic
'''
try:
my_conn = MongoConn()
check_connected(my_conn)
operation = {colum: 1}
return my_conn.db["infographic"].find({'_id': mongdb_id},)
except Exception:
LOGGER.error(traceback.format_exc())
测试使用
请确认MongoDB数据库已在服务器正常启动
(.venv) ➜ myproject ✗ python manage.py shell
Python 3.6.4 (v3.6.4:d48ecebad5, Dec 18 2017, 21:07:28)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from api import save as mongdb_save, find_one as mongdb_find, del_one as mongdb_delete
>>> test = {'test': 'this is just a test'}
>>> mongdb_save('test', test)
>>> result = mongdb_find('test', {'test': 'this is just a test'})
>>> result
{'_id': ObjectId('5b602baaf8aff5dd0b1dfab7'), 'test': 'this is just a test'}
>>> mongdb_delete('test', {'test': 'this is just a test'})
>>> result = mongdb_find('test', {'test': 'this is just a test'})
>>> result
>>>