ソースを参照

added unique constraint

version-14
Rushabh Mehta 10年前
コミット
be6b3f37a8
7個のファイルの変更113行の追加74行の削除
  1. +8
    -1
      frappe/core/doctype/custom_field/custom_field.json
  2. +1
    -0
      frappe/core/doctype/customize_form/customize_form.py
  3. +8
    -1
      frappe/core/doctype/customize_form_field/customize_form_field.json
  4. +8
    -1
      frappe/core/doctype/docfield/docfield.json
  5. +1
    -0
      frappe/data/Framework.sql
  6. +7
    -3
      frappe/model/__init__.py
  7. +80
    -68
      frappe/model/db_schema.py

+ 8
- 1
frappe/core/doctype/custom_field/custom_field.json ファイルの表示

@@ -145,6 +145,13 @@
"permlevel": 0, "permlevel": 0,
"search_index": 0 "search_index": 0
}, },
{
"fieldname": "unique",
"fieldtype": "Check",
"label": "Unique",
"permlevel": 0,
"precision": ""
},
{ {
"fieldname": "read_only", "fieldname": "read_only",
"fieldtype": "Check", "fieldtype": "Check",
@@ -267,7 +274,7 @@
], ],
"icon": "icon-glass", "icon": "icon-glass",
"idx": 1, "idx": 1,
"modified": "2014-09-05 07:41:13.076820",
"modified": "2014-09-26 05:04:49.148736",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Core", "module": "Core",
"name": "Custom Field", "name": "Custom Field",


+ 1
- 0
frappe/core/doctype/customize_form/customize_form.py ファイルの表示

@@ -31,6 +31,7 @@ class CustomizeForm(Document):
'width': 'Data', 'width': 'Data',
'print_width': 'Data', 'print_width': 'Data',
'reqd': 'Check', 'reqd': 'Check',
'unique': 'Check',
'ignore_user_permissions': 'Check', 'ignore_user_permissions': 'Check',
'in_filter': 'Check', 'in_filter': 'Check',
'in_list_view': 'Check', 'in_list_view': 'Check',


+ 8
- 1
frappe/core/doctype/customize_form_field/customize_form_field.json ファイルの表示

@@ -68,6 +68,13 @@
"search_index": 0, "search_index": 0,
"width": "50px" "width": "50px"
}, },
{
"fieldname": "unique",
"fieldtype": "Check",
"label": "Unique",
"permlevel": 0,
"precision": ""
},
{ {
"fieldname": "in_list_view", "fieldname": "in_list_view",
"fieldtype": "Check", "fieldtype": "Check",
@@ -278,7 +285,7 @@
"idx": 1, "idx": 1,
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"modified": "2014-09-05 07:41:29.641454",
"modified": "2014-09-26 05:06:37.372434",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Core", "module": "Core",
"name": "Customize Form Field", "name": "Customize Form Field",


+ 8
- 1
frappe/core/doctype/docfield/docfield.json ファイルの表示

@@ -78,6 +78,13 @@
"search_index": 0, "search_index": 0,
"width": "50px" "width": "50px"
}, },
{
"fieldname": "unique",
"fieldtype": "Check",
"label": "Unique",
"permlevel": 0,
"precision": ""
},
{ {
"fieldname": "in_list_view", "fieldname": "in_list_view",
"fieldtype": "Check", "fieldtype": "Check",
@@ -314,7 +321,7 @@
"in_dialog": 1, "in_dialog": 1,
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"modified": "2014-09-05 07:41:05.956027",
"modified": "2014-09-26 05:03:44.822570",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Core", "module": "Core",
"name": "DocField", "name": "DocField",


+ 1
- 0
frappe/data/Framework.sql ファイルの表示

@@ -30,6 +30,7 @@ CREATE TABLE `tabDocField` (
`print_hide` int(1) DEFAULT NULL, `print_hide` int(1) DEFAULT NULL,
`report_hide` int(1) DEFAULT NULL, `report_hide` int(1) DEFAULT NULL,
`reqd` int(1) DEFAULT NULL, `reqd` int(1) DEFAULT NULL,
`unique` int(1) DEFAULT NULL,
`no_copy` int(1) DEFAULT NULL, `no_copy` int(1) DEFAULT NULL,
`allow_on_submit` int(1) DEFAULT NULL, `allow_on_submit` int(1) DEFAULT NULL,
`trigger` varchar(255) DEFAULT NULL, `trigger` varchar(255) DEFAULT NULL,


+ 7
- 3
frappe/model/__init__.py ファイルの表示

@@ -7,9 +7,13 @@ import frappe
import json import json




no_value_fields = ['Section Break', 'Column Break', 'HTML', 'Table', 'Button', 'Image', 'Fold']
default_fields = ['doctype','name','owner','creation','modified','modified_by','parent','parentfield','parenttype','idx','docstatus']
integer_docfield_properties = ["reqd", "search_index", "in_list_view", "permlevel", "hidden", "read_only", "ignore_user_permissions", "allow_on_submit", "report_hide", "in_filter", "no_copy", "print_hide"]
no_value_fields = ['Section Break', 'Column Break', 'HTML', 'Table', 'Button',
'Image', 'Fold']
default_fields = ['doctype','name','owner','creation','modified','modified_by',
'parent','parentfield','parenttype','idx','docstatus']
integer_docfield_properties = ["reqd", "search_index", "in_list_view", "permlevel",
"hidden", "read_only", "ignore_user_permissions", "allow_on_submit", "report_hide",
"in_filter", "no_copy", "print_hide", "unique"]


def insert(doclist): def insert(doclist):
if not isinstance(doclist, list): if not isinstance(doclist, list):


+ 80
- 68
frappe/model/db_schema.py ファイルの表示

@@ -36,14 +36,27 @@ type_map = {
,'Attach': ('varchar', '255') ,'Attach': ('varchar', '255')
} }


default_columns = ['name', 'creation', 'modified', 'modified_by', 'owner', 'docstatus', 'parent',\
'parentfield', 'parenttype', 'idx']
default_columns = ['name', 'creation', 'modified', 'modified_by', 'owner',
'docstatus', 'parent', 'parentfield', 'parenttype', 'idx']


default_shortcuts = ['_Login', '__user', '_Full Name', 'Today', '__today'] default_shortcuts = ['_Login', '__user', '_Full Name', 'Today', '__today']


# -------------------------------------------------
# Class database table
# -------------------------------------------------
def updatedb(dt):
"""
Syncs a `DocType` to the table
* creates if required
* updates columns
* updates indices
"""
res = frappe.db.sql("select ifnull(issingle, 0) from tabDocType where name=%s", (dt,))
if not res:
raise Exception, 'Wrong doctype "%s" in updatedb' % dt

if not res[0][0]:
frappe.db.commit()
tab = DbTable(dt, 'tab')
tab.sync()
frappe.db.begin()


class DbTable: class DbTable:
def __init__(self, doctype, prefix = 'tab'): def __init__(self, doctype, prefix = 'tab'):
@@ -55,13 +68,21 @@ class DbTable:
# lists for change # lists for change
self.add_column = [] self.add_column = []
self.change_type = [] self.change_type = []

self.add_index = [] self.add_index = []
self.drop_index = [] self.drop_index = []

self.set_default = [] self.set_default = []


# load # load
self.get_columns_from_docfields() self.get_columns_from_docfields()


def sync(self):
if not self.name in DbManager(frappe.db).get_tables_list(frappe.db.cur_db_name):
self.create()
else:
self.alter()

def create(self): def create(self):
add_text = '' add_text = ''


@@ -89,6 +110,25 @@ class DbTable:
ENGINE=InnoDB ENGINE=InnoDB
CHARACTER SET=utf8""" % (self.name, add_text)) CHARACTER SET=utf8""" % (self.name, add_text))


def get_column_definitions(self):
column_list = [] + default_columns
ret = []
for k in self.columns.keys():
if k not in column_list:
d = self.columns[k].get_definition()
if d:
ret.append('`'+ k+ '` ' + d)
column_list.append(k)
return ret

def get_index_definitions(self):
ret = []
for key, col in self.columns.items():
if col.set_index and col.fieldtype in type_map and \
type_map.get(col.fieldtype)[0] not in ('text', 'longtext'):
ret.append('index `' + key + '`(`' + key + '`)')
return ret

def get_columns_from_docfields(self): def get_columns_from_docfields(self):
""" """
get columns from docfields and custom fields get columns from docfields and custom fields
@@ -107,32 +147,13 @@ class DbTable:
for f in fl: for f in fl:
self.columns[f['fieldname']] = DbColumn(self, f['fieldname'], self.columns[f['fieldname']] = DbColumn(self, f['fieldname'],
f['fieldtype'], f.get('length'), f.get('default'), f['fieldtype'], f.get('length'), f.get('default'),
f.get('search_index'), f.get('options'))
f.get('search_index'), f.get('options'), f.get('unique'))


def get_columns_from_db(self): def get_columns_from_db(self):
self.show_columns = frappe.db.sql("desc `%s`" % self.name) self.show_columns = frappe.db.sql("desc `%s`" % self.name)
for c in self.show_columns: for c in self.show_columns:
self.current_columns[c[0]] = {'name': c[0], 'type':c[1], 'index':c[3], 'default':c[4]}

def get_column_definitions(self):
column_list = [] + default_columns
ret = []
for k in self.columns.keys():
if k not in column_list:
d = self.columns[k].get_definition()
if d:
ret.append('`'+ k+ '` ' + d)
column_list.append(k)
return ret

def get_index_definitions(self):
ret = []
for key, col in self.columns.items():
if col.set_index and col.fieldtype in type_map and \
type_map.get(col.fieldtype)[0] not in ('text', 'longtext'):
ret.append('index `' + key + '`(`' + key + '`)')
return ret

self.current_columns[c[0]] = {'name': c[0],
'type':c[1], 'index':c[3]=="MUL", 'default':c[4], "unique":c[3]=="UNI"}


# GET foreign keys # GET foreign keys
def get_foreign_keys(self): def get_foreign_keys(self):
@@ -165,16 +186,10 @@ class DbTable:
frappe.db.sql("alter table `%s` drop foreign key `%s`" % (self.name, fk_dict[col.fieldname])) frappe.db.sql("alter table `%s` drop foreign key `%s`" % (self.name, fk_dict[col.fieldname]))
frappe.db.sql("set foreign_key_checks=1") frappe.db.sql("set foreign_key_checks=1")


def sync(self):
if not self.name in DbManager(frappe.db).get_tables_list(frappe.db.cur_db_name):
self.create()
else:
self.alter()

def alter(self): def alter(self):
self.get_columns_from_db() self.get_columns_from_db()
for col in self.columns.values(): for col in self.columns.values():
col.check(self.current_columns.get(col.fieldname, None))
col.build_for_alter_table(self.current_columns.get(col.fieldname, None))


query = [] query = []


@@ -193,11 +208,12 @@ class DbTable:
for col in self.drop_index: for col in self.drop_index:
if col.fieldname != 'name': # primary key if col.fieldname != 'name': # primary key
# if index key exists # if index key exists
if frappe.db.sql("show index from `%s` where key_name = %s" %
(self.name, '%s'), col.fieldname):
if frappe.db.sql("""show index from `{0}`
where key_name=%s
and Non_unique=%s""".format(self.name), (col.fieldname, 1 if col.unique else 0), debug=1):
query.append("drop index `{}`".format(col.fieldname)) query.append("drop index `{}`".format(col.fieldname))


for col in list(set(self.set_default).difference(set(self.change_type))):
for col in self.set_default:
if col.fieldname=="name": if col.fieldname=="name":
continue continue


@@ -212,7 +228,8 @@ class DbTable:
frappe.db.sql("alter table `{}` {}".format(self.name, ", ".join(query))) frappe.db.sql("alter table `{}` {}".format(self.name, ", ".join(query)))


class DbColumn: class DbColumn:
def __init__(self, table, fieldname, fieldtype, length, default, set_index, options):
def __init__(self, table, fieldname, fieldtype, length, default,
set_index, options, unique):
self.table = table self.table = table
self.fieldname = fieldname self.fieldname = fieldname
self.fieldtype = fieldtype self.fieldtype = fieldtype
@@ -220,18 +237,22 @@ class DbColumn:
self.set_index = set_index self.set_index = set_index
self.default = default self.default = default
self.options = options self.options = options
self.unique = unique


def get_definition(self, with_default=1):
ret = get_definition(self.fieldtype)
def get_definition(self):
column_def = get_definition(self.fieldtype)


if with_default and self.default and (self.default not in default_shortcuts) \
and not self.default.startswith(":") and ret not in ['text', 'longtext']:
ret += ' default "' + self.default.replace('"', '\"') + '"'
if self.default and (self.default not in default_shortcuts) \
and not self.default.startswith(":") and column_def not in ['text', 'longtext']:
column_def += ' default "' + self.default.replace('"', '\"') + '"'


return ret
if self.unique:
column_def += ' unique'

return column_def


def check(self, current_def):
column_def = self.get_definition(0)
def build_for_alter_table(self, current_def):
column_def = get_definition(self.fieldtype)


# no columns # no columns
if not column_def: if not column_def:
@@ -244,20 +265,27 @@ class DbColumn:
return return


# type # type
if current_def['type'] != column_def:
if (current_def['type'] != column_def) or (self.unique and not current_def['unique']):
self.table.change_type.append(self) self.table.change_type.append(self)


# index
else: else:
# index
if (current_def['index'] and not self.set_index): if (current_def['index'] and not self.set_index):
self.table.drop_index.append(self) self.table.drop_index.append(self)


if (current_def['unique'] and not self.unique):
self.table.drop_index.append(self)

if (not current_def['index'] and self.set_index and not (column_def in ['text', 'longtext'])): if (not current_def['index'] and self.set_index and not (column_def in ['text', 'longtext'])):
self.table.add_index.append(self) self.table.add_index.append(self)


# default
if (self.default_changed(current_def) and (self.default not in default_shortcuts) and not cstr(self.default).startswith(":") and not (column_def in ['text','longtext'])):
self.table.set_default.append(self)
# default
if (self.default_changed(current_def) \
and (self.default not in default_shortcuts) \
and not cstr(self.default).startswith(":") \
and not (column_def in ['text','longtext'])):
self.table.set_default.append(self)





def default_changed(self, current_def): def default_changed(self, current_def):
@@ -373,22 +401,6 @@ def validate_column_name(n):
return n return n




def updatedb(dt):
"""
Syncs a `DocType` to the table
* creates if required
* updates columns
* updates indices
"""
res = frappe.db.sql("select ifnull(issingle, 0) from tabDocType where name=%s", (dt,))
if not res:
raise Exception, 'Wrong doctype "%s" in updatedb' % dt

if not res[0][0]:
frappe.db.commit()
tab = DbTable(dt, 'tab')
tab.sync()
frappe.db.begin()


def remove_all_foreign_keys(): def remove_all_foreign_keys():
frappe.db.sql("set foreign_key_checks = 0") frappe.db.sql("set foreign_key_checks = 0")
@@ -417,8 +429,8 @@ def get_definition(fieldtype):
ret += '(' + d[1] + ')' ret += '(' + d[1] + ')'
return ret return ret



def add_column(doctype, column_name, fieldtype): def add_column(doctype, column_name, fieldtype):
"""Add a column to the database"""
frappe.db.commit() frappe.db.commit()
frappe.db.sql("alter table `tab%s` add column %s %s" % (doctype, frappe.db.sql("alter table `tab%s` add column %s %s" % (doctype,
column_name, get_definition(fieldtype))) column_name, get_definition(fieldtype)))


読み込み中…
キャンセル
保存