Kingbase(金仓数据库)是北京人大金仓信息技术股份有限公司经过多年努力,自主研制开发的具有自主知识产权的通用关系型数据库管理系统,属于国产数据库,在与其他软件的连接上参考资料较少。作者由于实验要求使用此数据库开发,期间遇到很多问题,最后经过老师的一篇文档完成实验。写下此文章以便参考。
Python 3.6
Django 1.8
KingbaseES 7.0
下载地址: https://www.python.org/downloads/
在此网站下载python 并安装。一定要勾选pip。注意勾选第一个安装界面的下部分加入path的选项。
图片:
• 在命令提示符下用安装django:
A. 打开命令提示符窗口(win+R,输入cmd)
B. 执行django 安装命令: pip install Django
使用pip install psycopg2 安装
(1) 安装数据库
(2) 初始化数据库
使用下图所示的“数据库初始化工具”。 完成后,任务管理器的“服务”会发现对应的kingbase_instance。
具体安装教程参照kingbase相关文件。
django-admin.py startproject HelloWorld
生成结果如下:
使用命令 django-admin startapp TestModel
配置TestModel参照:http://www.runoob.com/django/django-tutorial.html
Django中内置了多种数据库,如postgresql、oracle、mysql,如果使用kingbase数据库,需要自己定制数据库后台,详见第三部分:定制数据库后台。
HelloWorld/HelloWorld/settings.py: 文件代码
DATABASES = {
'default': {
‘ENGINE’: ‘TestModel.backends.kingbase’, # kingbase
‘NAME’: ‘HELLO’, # 数据库名,已创建
‘USER’: ‘SYSTEM’, #用户名
‘PASSWORD’: ‘123456’, #密码
‘HOST’: ‘127.0.0.1’, #服务器所在ip
‘PORT’: ‘54321’, #端口号
}
}
A .使用python manage.py makemigrations , 通知Django修改Model, TestModel\migrations下生成0001_initial.py
B. python manage.py sqlmigrate , 查看model对应的SQL语句
C . python manage.py migrate , 执行SQL语句到数据库
注意:如果使用命令行语句不能自动执行,则需要在python平台手动执行,对于第三步则需要将生成的0001_initial中SQL语句复制到数据库中执行。
查看kingbase中HELLO数据库,发现自动生成数据库表。
7 在view中使用model,渲染相应的模板(html)
8 在url中创建请求和响应(view)的映射
9 将在模板(html)中使用Form表单简化html控件
7.8.9同网上参考教程.
由于kingbase的底层是postgresql,使用psycog2能够连接kingbase,因此我们继承已有的postgresql数据库后台,修改kingbase特有的部分。
A. 在TestModel目录下创建backends\kingbase文件夹,在kingbase文件夹下创建3个文件: init.py,base.py,introspection.py
B. init.py 内容为空,告诉python这是python文件而已。
C. base.py 中代码如下:
from django.db.backends.postgresql import base # 从postgresql中导入base
from .introspection import DatabaseIntrospection #从introspection.py导入DatabaseIntrospection类
class DatabaseWrapper(base.DatabaseWrapper): #继承postgresql的DatabaseWrapper
data_types = {
'AutoField': 'int identity(1,1)', #设置 Model Field和kingbase数据类型的转换
'BigAutoField': 'bigserial',
'BinaryField': 'bytea',
'BooleanField': 'boolean',
'CharField': 'varchar(%(max_length)s)',
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'timestamp with time zone',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'interval',
'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision',
'IntegerField': 'integer',
'BigIntegerField': 'bigint',
'IPAddressField': 'inet',
'GenericIPAddressField': 'inet',
'NullBooleanField': 'boolean',
'OneToOneField': 'integer',
'PositiveIntegerField': 'integer',
'PositiveSmallIntegerField': 'smallint',
'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'text',
'TimeField': 'time',
'UUIDField': 'uuid',
}
introspection_class = DatabaseIntrospection # introspection_class类使用introspection.py中DatabaseIntrospection类
def get_new_connection(self, conn_params):
conn = super(DatabaseWrapper,
self).get_new_connection(conn_params)
return conn
D. introspection.py 中代码如下:
主要修改kingbase与postgresql不同的系统命名表(postgresql中用pg_作前缀,kingbase中用sys_做前缀)和其他不一致的地方。
from django.db.backends.base.introspection import TableInfo
from django.db.backends.postgresql import introspection
class DatabaseIntrospection(introspection.DatabaseIntrospection):
_get_indexes_query = """
SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary
FROM sys_catalog.sys_class c, sys_catalog.sys_class c2,
sys_catalog.sys_index idx, sys_catalog.sys_attribute attr
WHERE c.oid = idx.indrelid
AND idx.indexrelid = c2.oid
AND attr.attrelid = c.oid
AND attr.attnum = idx.indkey[0]
AND c.relname = %s"""
def get_table_list(self, cursor):
"""
Returns a list of table and view names in the current database.
"""
cursor.execute("""
SELECT c.relname, c.relkind
FROM sys_catalog.sys_class c
LEFT JOIN sys_catalog.sys_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r', 'v')
AND n.nspname NOT IN ('sys_catalog', 'sys_toast')
AND sys_catalog.sys_table_is_visible(c.oid)""")
return [TableInfo(row[0], {
'r': 't', 'v': 'v'}.get(row[1]))
for row in cursor.fetchall()
if row[0] not in self.ignored_tables]
def get_relations(self, cursor, table_name):
"""
Returns a dictionary of {
field_name: (field_name_other_table, other_table)}
representing all relationships to the given table.
"""
cursor.execute("""
SELECT c2.relname, a1.attname, a2.attname
FROM sys_constraint con
LEFT JOIN sys_class c1 ON con.conrelid = c1.oid
LEFT JOIN sys_class c2 ON con.confrelid = c2.oid
LEFT JOIN sys_attribute a1 ON c1.oid = a1.attrelid AND a1.attnum = con.conkey[1]
LEFT JOIN sys_attribute a2 ON c2.oid = a2.attrelid AND a2.attnum = con.confkey[1]
WHERE c1.relname = %s
AND con.contype = 'f'""", [table_name])
relations = {
}
for row in cursor.fetchall():
relations[row[1]] = (row[2], row[0])
return relations
def get_constraints(self, cursor, table_name):
"""
Retrieve any constraints or keys (unique, pk, fk, check, index) across
one or more columns. Also retrieve the definition of expression-based
indexes.
"""
constraints = {
}
# Loop over the key table, collecting things as constraints. The column
# array must return column names in the same order in which they were
# created.
# The subquery containing generate_series can be replaced with
# "WITH ORDINALITY" when support for PostgreSQL 9.3 is dropped.
cursor.execute("""
SELECT
c.conname,
array(
SELECT attname
FROM (
SELECT unnest(c.conkey) AS colid,
generate_series(1, array_length(c.conkey, 1)) AS arridx
) AS cols
JOIN sys_attribute AS ca ON cols.colid = ca.attnum
WHERE ca.attrelid = c.conrelid
ORDER BY cols.arridx
),
c.contype,
(SELECT fkc.relname || '.' || fka.attname
FROM sys_attribute AS fka
JOIN sys_class AS fkc ON fka.attrelid = fkc.oid
WHERE fka.attrelid = c.confrelid AND fka.attnum = c.confkey[1]),
cl.reloptions
FROM sys_constraint AS c
JOIN sys_class AS cl ON c.conrelid = cl.oid
JOIN sys_namespace AS ns ON cl.relnamespace = ns.oid
WHERE ns.nspname = %s AND cl.relname = %s
""", ["public", table_name])
for constraint, columns, kind, used_cols, options in cursor.fetchall():
constraints[constraint] = {
"columns": columns,
"primary_key": kind == "p",
"unique": kind in ["p", "u"],
"foreign_key": tuple(used_cols.split(".", 1)) if kind == "f" else None,
"check": kind == "c",
"index": False,
"definition": None,
"options": options,
}
# Now get indexes
# The row_number() function for ordering the index fields can be
# replaced by WITH ORDINALITY in the unnest() functions when support
# for PostgreSQL 9.3 is dropped.
cursor.execute("""
SELECT
indexname, array_agg(attname), indisunique, indisprimary,
array_agg(ordering), amname, exprdef, s2.attoptions
FROM (
SELECT
row_number() OVER () as rnum, c2.relname as indexname,
idx.*, attr.attname, am.amname,
CASE
WHEN idx.indexprs IS NOT NULL THEN
sys_get_indexdef(idx.indexrelid)
END AS exprdef,
CASE am.amname
WHEN 'btree' THEN
CASE (option & 1)
WHEN 1 THEN 'DESC' ELSE 'ASC'
END
END as ordering,
c2.reloptions as attoptions
FROM (
SELECT
*, unnest(i.indkey) as key, unnest(i.indoption) as option
FROM sys_index i
) idx
LEFT JOIN sys_class c ON idx.indrelid = c.oid
LEFT JOIN sys_class c2 ON idx.indexrelid = c2.oid
LEFT JOIN sys_am am ON c2.relam = am.oid
LEFT JOIN sys_attribute attr ON attr.attrelid = c.oid AND attr.attnum = idx.key
WHERE c.relname = %s
) s2
GROUP BY indexname, indisunique, indisprimary, amname, exprdef, attoptions;
""", [table_name])
for index, columns, unique, primary, orders, type_, definition, options in cursor.fetchall():
if index not in constraints:
constraints[index] = {
"columns": columns if columns != [None] else [],
"orders": orders if orders != [None] else [],
"primary_key": primary,
"unique": unique,
"foreign_key": None,
"check": False,
"index": True,
"type": Index.suffix if type_ == 'btree' else type_,
"definition": definition,
"options": options,
}
return constraints
至此,Django搭建完成,读者可以根据自己的需求开发相应的系统。